﻿/*****************************************************************************
 * metaname.c
 *
 * DESCRIPTION
 *    This file contains the code necessary to parse the GRIB2 product
 * definition information into human readable text.  In addition to the
 * tables in the GRIB2 specs, it also attempts to handle local table
 * definitions that NCEP and NDFD have developed.
 *
 * HISTORY
 *    1/2004 Arthur Taylor (MDL / RSIS): Created.
 *
 * NOTES
 *****************************************************************************
 */
#include <string.h>
#include <stdlib.h>
#include <limits>
#include "meta.h"
#include "metaname.h"
#include "myerror.h"
#include "myassert.h"
#include "myutil.h"
#include "OCMain/Environment.h"
#include "degrib1.h"
#include "OCMain/Log.h"

using namespace OCPP;

#pragma warning(disable:4566)


#define CPLIsNan(x) std::isnan(x)
#define CPLSPrintf sprintf
#define FALSE 0
#define TRUE 1


const GRIB2SurfTable grib2_table_4_2_0_0[30] = {
    /*0*/{"TMP","Temperature","K","UC_K2F"},
    /*1*/{"VTMP","Virtual temperature","K","UC_K2F"},
    /*2*/{"POT","Potential temperature","K","UC_K2F"},
    /*3*/{"EPOT","Pseudo-adiabatic potential temperature","K","UC_K2F"},
    /*4*/{"TMAX","Maximum temperature","K","UC_K2F"},
    /*5*/{"TMIN","Minimum temperature","K","UC_K2F"},
    /*6*/{"DPT","Dew point temperature","K","UC_K2F"},
    /*7*/{"DEPR","Dew point depression","K","UC_NONE"},
    /*8*/{"LAPR","Lapse rate","K/m","UC_NONE"},
    /*9*/{"TMPA","Temperature anomaly","K","UC_K2F"},
    /*10*/{"LHTFL","Latent heat net flux","W/(m^2)","UC_NONE"},
    /*11*/{"SHTFL","Sensible heat net flux","W/(m^2)","UC_NONE"},
    /*12*/{"HEATX","Heat index","K","UC_K2F"},
    /*13*/{"WCF","Wind chill factor","K","UC_K2F"},
    /*14*/{"MINDPD","Minimum dew point depression","K","UC_K2F"},
    /*15*/{"VPTMP","Virtual potential temperature","K","UC_K2F"},
    /*16*/{"SNOHF","Snow phase change heat flux","W/m^2","UC_NONE"},
    /*17*/{"SKINT","Skin temperature","K","UC_K2F"},
    /*18*/{"SNOT","Snow Temperature (top of snow)","K","UC_K2F"},
    /*19*/{"TTCHT","Turbulent Transfer Coefficient for Heat","Numeric","UC_NONE"},
    /*20*/{"TDCHT","Turbulent Diffusion Coefficient for Heat","m^2/s","UC_NONE"},
    /*21*/{"APTMP","Apparent Temperature","K","UC_K2F"},
    /*22*/{"TTSWR","Temperature Tendency due to Short-Wave Radiation","K/s","UC_NONE"},
    /*23*/{"TTLWR","Temperature Tendency due to Long-Wave Radiation","K/s","UC_NONE"},
    /*24*/{"TTSWRCS","Temperature Tendency due to Short-Wave Radiation,  Clear Sky","K/s","UC_NONE"},
    /*25*/{"TTLWRCS","Temperature Tendency due to Long-Wave Radiation,  Clear Sky","K/s","UC_NONE"},
    /*26*/{"TTPARM","Temperature Tendency due to parameterizations","K/s","UC_NONE"},
    /*27*/{"WETBT","Wet Bulb Temperature","K","UC_K2F"},
    /*28*/{"UCTMP","Unbalanced Component of Temperature","K","UC_K2F"},
    /*29*/{"TMPADV","Temperature Advection","K/s","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_1[122] = {
    /*0*/{"SPFH","Specific humidity","kg/kg","UC_NONE"},
    /*1*/{"RH","Relative humidity","%","UC_NONE"},
    /*2*/{"MIXR","Humidity mixing ratio","kg/kg","UC_NONE"},
    /*3*/{"PWAT","Precipitable water","kg/(m^2)","UC_NONE"},
    /*4*/{"VAPP","Vapor pressure","Pa","UC_NONE"},
    /*5*/{"SATD","Saturation deficit","Pa","UC_NONE"},
    /*6*/{"EVP","Evaporation","kg/(m^2)","UC_InchWater"},
    /*7*/{"PRATE","Precipitation rate","kg/(m^2 s)","UC_NONE"},
    /*8*/{"APCP","Total precipitation","kg/(m^2)","UC_InchWater"},
    /*9*/{"NCPCP","Large scale precipitation","kg/(m^2)","UC_NONE"},
    /*10*/{"ACPCP","Convective precipitation","kg/(m^2)","UC_NONE"},
    /*11*/{"SNOD","Snow depth","m","UC_M2Inch"},
    /*12*/{"SRWEQ","Snowfall rate water equivalent","kg/(m^2 s)","UC_NONE"},
    /*13*/{"WEASD","Water equivalent of accumulated snow depth","kg/(m^2)","UC_NONE"},
    /*14*/{"SNOC","Convective snow","kg/(m^2)","UC_NONE"},
    /*15*/{"SNOL","Large scale snow","kg/(m^2)","UC_NONE"},
    /*16*/{"SNOM","Snow melt","kg/(m^2)","UC_NONE"},
    /*17*/{"SNOAG","Snow age","day","UC_NONE"},
    /*18*/{"ABSH","Absolute humidity","kg/(m^3)","UC_NONE"},
    /*19*/{"PTYPE","Precipitation type","1=Rain; 2=Thunderstorm; 3=Freezing Rain; 4=Mixed/ice; 5=snow; 255=missing","UC_NONE"},
    /*20*/{"ILIQW","Integrated liquid water","kg/(m^2)","UC_NONE"},
    /*21*/{"TCOND","Condensate","kg/kg","UC_NONE"},
    /*22*/{"CLWMR","Cloud mixing ratio","kg/kg","UC_NONE"},
    /*23*/{"ICMR","Ice water mixing ratio","kg/kg","UC_NONE"},
    /*24*/{"RWMR","Rain mixing ratio","kg/kg","UC_NONE"},
    /*25*/{"SNMR","Snow mixing ratio","kg/kg","UC_NONE"},
    /*26*/{"MCONV","Horizontal moisture convergence","kg/(kg s)","UC_NONE"},
    /*27*/{"MAXRH","Maximum relative humidity","%","UC_NONE"},
    /*28*/{"MAXAH","Maximum absolute humidity","kg/(m^3)","UC_NONE"},
    /*29*/{"ASNOW","Total snowfall","m","UC_M2Inch"},
    /*30*/{"PWCAT","Precipitable water category","undefined","UC_NONE"},
    /*31*/{"HAIL","Hail","m","UC_NONE"},
    /*32*/{"GRLE","Graupel (snow pellets)","kg/kg","UC_NONE"},
    /*33*/{"CRAIN","Categorical rain","0=no; 1=yes","UC_NONE"},
    /*34*/{"CFRZR","Categorical freezing rain","0=no; 1=yes","UC_NONE"},
    /*35*/{"CICEP","Categorical ice pellets","0=no; 1=yes","UC_NONE"},
    /*36*/{"CSNOW","Categorical snow","0=no; 1=yes","UC_NONE"},
    /*37*/{"CPRAT","Convective precipitation rate","kg/(m^2*s)","UC_NONE"},
    /*38*/{"MCONV","Horizontal moisture divergence","kg/(kg*s)","UC_NONE"},
    /*39*/{"CPOFP","Percent frozen precipitation","%","UC_NONE"},
    /*40*/{"PEVAP","Potential evaporation","kg/m^2","UC_NONE"},
    /*41*/{"PEVPR","Potential evaporation rate","W/m^2","UC_NONE"},
    /*42*/{"SNOWC","Snow cover","%","UC_NONE"},
    /*43*/{"FRAIN","Rain fraction of total cloud water","-","UC_NONE"},
    /*44*/{"RIME","Rime factor","-","UC_NONE"},
    /*45*/{"TCOLR","Total column integrated rain","kg/m^2","UC_NONE"},
    /*46*/{"TCOLS","Total column integrated snow","kg/m^2","UC_NONE"},
    /*47*/{"LSWP","Large scale water precipitation","kg/m^2","UC_NONE"},
    /*48*/{"CWP","Convective water precipitation","kg/m^2","UC_NONE"},
    /*49*/{"TWATP","Total water precipitation","kg/m^2","UC_NONE"},
    /*50*/{"TSNOWP","Total snow precipitation","kg/m^2","UC_NONE"},
    /*51*/{"TCWAT","Total column water","kg/m^2","UC_NONE"},
    /*52*/{"TPRATE","Total precipitation rate","kg/(m^2*s)","UC_NONE"},
    /*53*/{"TSRWE","Total snowfall rate water equivalent","kg/(m^2*s)","UC_NONE"},
    /*54*/{"LSPRATE","Large scale precipitation rate","kg/(m^2*s)","UC_NONE"},
    /*55*/{"CSRWE","Convective snowfall rate water equivalent","kg/(m^2*s)","UC_NONE"},
    /*56*/{"LSSRWE","Large scale snowfall rate water equivalent","kg/(m^2*s)","UC_NONE"},
    /*57*/{"TSRATE","Total snowfall rate","m/s","UC_NONE"},
    /*58*/{"CSRATE","Convective snowfall rate","m/s","UC_NONE"},
    /*59*/{"LSSRWE","Large scale snowfall rate","m/s","UC_NONE"},
    /*60*/{"SDWE","Snow depth water equivalent","kg/m^2","UC_NONE"},
    /*61*/{"SDEN","Snow density","kg/m^3","UC_NONE"},
    /*62*/{"SEVAP","Snow evaporation","kg/m^2","UC_NONE"},
    /*63*/{"","Reserved","-","UC_NONE"},
    /*64*/{"TCIWV","Total column integrated water vapour","kg/m^2","UC_NONE"},
    /*65*/{"RPRATE","Rain precipitation rate","kg/(m^2*s)","UC_NONE"},
    /*66*/{"SPRATE","Snow precipitation rate","kg/(m^2*s)","UC_NONE"},
    /*67*/{"FPRATE","Freezing rain precipitation rate","kg/(m^2*s)","UC_NONE"},
    /*68*/{"IPRATE","Ice pellets precipitation rate","kg/(m^2*s)","UC_NONE"},
    /*69*/{"TCOLW","Total Column Integrate Cloud Water","kg/m^2","UC_NONE"},
    /*70*/{"TCOLI","Total Column Integrate Cloud Ice","kg/m^2","UC_NONE"},
    /*71*/{"HAILMXR","Hail Mixing Ratio","kg/kg","UC_NONE"},
    /*72*/{"TCOLH","Total Column Integrate Hail","kg/m^2","UC_NONE"},
    /*73*/{"HAILPR","Hail Prepitation Rate","kg/(m^2*s)","UC_NONE"},
    /*74*/{"TCOLG","Total Column Integrate Graupel","kg/m^2","UC_NONE"},
    /*75*/{"GPRATE","Graupel (Snow Pellets) Prepitation Rate","kg/(m^2*s)","UC_NONE"},
    /*76*/{"CRRATE","Convective Rain Rate","kg/(m^2*s)","UC_NONE"},
    /*77*/{"LSRRATE","Large Scale Rain Rate","kg/(m^2*s)","UC_NONE"},
    /*78*/{"TCOLWA","Total Column Integrate Water (All components including precipitation)","kg/m^2","UC_NONE"},
    /*79*/{"EVARATE","Evaporation Rate","kg/(m^2*s)","UC_NONE"},
    /*80*/{"TOTCON","Total Condensate","kg/kg","UC_NONE"},
    /*81*/{"TCICON","Total Column-Integrate Condensate","kg/m^2","UC_NONE"},
    /*82*/{"CIMIXR","Cloud Ice Mixing Ratio","kg/kg","UC_NONE"},
    /*83*/{"SCLLWC","Specific Cloud Liquid Water Content","kg/kg","UC_NONE"},
    /*84*/{"SCLIWC","Specific Cloud Ice Water Content","kg/kg","UC_NONE"},
    /*85*/{"SRAINW","Specific Rain Water Content","kg/kg","UC_NONE"},
    /*86*/{"SSNOWW","Specific Snow Water Content","kg/kg","UC_NONE"},
    /*87*/{"SPRATE","Stratiform Precipitation Rate","kg/(m^2*s)","UC_NONE"},
    /*88*/{"CATCP","Categorical Convective Precipitation","0=No; 1=Yes; 2-191=Reserved; 192-254=Reserved; 255=missing","UC_NONE"},
    /*89*/{"","Reserved","-","UC_NONE"},
    /*90*/{"TKMFLX","Total Kinematic Moisture Flux","kg/kg(m/s)","UC_NONE"},
    /*91*/{"UKMFLX","U-component (zonal) Kinematic Moisture Flux","kg/kg(m/s)","UC_NONE"},
    /*92*/{"VKMFLX","V-component (meridional) Kinematic Moisture Flux","kg/kg(m/s)","UC_NONE"},
    /*93*/{"RHWATER","Relative Humidity With Respect to Water","%","UC_NONE"},
    /*94*/{"RHICE","Relative Humidity With Respect to Ice","%","UC_NONE"},
    /*95*/{"FZPRATE","Freezing or Frozen Precipitation Rate","kg/(m^2*s)","UC_NONE"},
    /*96*/{"MASSDR","Mass Density of Rain","kg/m^3","UC_NONE"},
    /*97*/{"MASSDS","Mass Density of Snow","kg/m^3","UC_NONE"},
    /*98*/{"MASSDG","Mass Density of Graupel","kg/m^3","UC_NONE"},
    /*99*/{"MASSDH","Mass Density of Hail","kg/m^3","UC_NONE"},
    /*100*/{"SPNCR","Specific Number Concentration of Rain","kg^-1","UC_NONE"},
    /*101*/{"SPNCS","Specific Number Concentration of Snow","kg^-1","UC_NONE"},
    /*102*/{"SPNCG","Specific Number Concentration of Graupel","kg^-1","UC_NONE"},
    /*103*/{"SPNCH","Specific Number Concentration of Hail","kg^-1","UC_NONE"},
    /*104*/{"NUMDR","Number Density of Rain","m^-3","UC_NONE"},
    /*105*/{"NUMDS","Number Density of Snow","m^-3","UC_NONE"},
    /*106*/{"NUMDG","Number Density of Graupel","m^-3","UC_NONE"},
    /*107*/{"NUMDH","Number Density of Hail","m^-3","UC_NONE"},
    /*108*/{"SHTPRM","Specific Humidity Tendency due to Parameterizations","kg/kg(s)","UC_NONE"},
    /*109*/{"MDLWHVA","Mass Density of Liquid Water Coating on Hail Expressed as Mass of Liquid Water per Unit Volume of Air","kg/m^3","UC_NONE"},
    /*110*/{"SMLWHMA","Specific Mass of Liquid Water Coating on Hail Expressed as Mass of Liquid Water per Unit Mass of Moist Air","kg/kg","UC_NONE"},
    /*111*/{"MMLWHDA","Mass Mixing Ratio of Liquid Water Coating on Hail Expressed as Mass of Liquid Water per Unit Mass of Dry Air","kg/kg","UC_NONE"},
    /*112*/{"MDLWGVA","Mass Density of Liquid Water Coating on Graupel Expressed as Mass of Liquid Water per Unit Volume of Air","kg/m^3","UC_NONE"},
    /*113*/{"SMLWGMA","Specific Mass of Liquid Water Coating on Graupel Expressed as Mass of Liquid Water per Unit Mass of Moist Air","kg/kg","UC_NONE"},
    /*114*/{"MMLWGDA","Mass Mixing Ratio of Liquid Water Coating on Graupel Expressed as Mass of Liquid Water per Unit Mass of Dry Air","kg/kg","UC_NONE"},
    /*115*/{"MDLWSVA","Mass Density of Liquid Water Coating on Snow Expressed as Mass of Liquid Water per Unit Volume of Air","kg/m^3","UC_NONE"},
    /*116*/{"SMLWSMA","Specific Mass of Liquid Water Coating on Snow Expressed as Mass of Liquid Water per Unit Mass of Moist Air","kg/kg","UC_NONE"},
    /*117*/{"MMLWSDA","Mass Mixing Ratio of Liquid Water Coating on Snow Expressed as Mass of Liquid Water per Unit Mass of Dry Air","kg/kg","UC_NONE"},
    /*118*/{"UNCSH","Unbalanced Component of Specific Humidity","kg/kg","UC_NONE"},
    /*119*/{"UCSCLW","Unbalanced Component of Specific Cloud Liquid Water content","kg/kg","UC_NONE"},
    /*120*/{"UCSCIW","Unbalanced Component of Specific Cloud Ice Water content","kg/kg","UC_NONE"},
    /*121*/{"FSNOWC","Fraction of Snow Cover","Proportion","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_13[1] = {
    /*0*/{"AEROT","Aerosol type","0=Aerosol not present; 1=Aerosol present; 255=missing","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_14[3] = {
    /*0*/{"TOZNE","Total ozone","Dobson","UC_NONE"},
    /*1*/{"O3MR","Ozone mixing ratio","kg/kg","UC_NONE"},
    /*2*/{"TCIOZ","Total column integrated ozone","Dobson","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_15[17] = {
    /*0*/{"BSWID","Base spectrum width","m/s","UC_NONE"},
    /*1*/{"BREF","Base reflectivity","dB","UC_NONE"},
    /*2*/{"BRVEL","Base radial velocity","m/s","UC_NONE"},
    /*3*/{"VERIL","Vertically-integrated liquid","kg/m","UC_NONE"},
    /*4*/{"LMAXBR","Layer maximum base reflectivity","dB","UC_NONE"},
    /*5*/{"PREC","Precipitation","kg/(m^2)","UC_NONE"},
    /*6*/{"RDSP1","Radar spectra (1)","-","UC_NONE"},
    /*7*/{"RDSP2","Radar spectra (2)","-","UC_NONE"},
    /*8*/{"RDSP3","Radar spectra (3)","-","UC_NONE"},
    /*9*/{"RFCD","Reflectivity of Cloud Droplets","dB","UC_NONE"},
    /*10*/{"RFCI","Reflectivity of Cloud Ice","dB","UC_NONE"},
    /*11*/{"RFSNOW","Reflectivity of Snow","dB","UC_NONE"},
    /*12*/{"RFRAIN","Reflectivity of Rain","dB","UC_NONE"},
    /*13*/{"RFGRPL","Reflectivity of Graupel","dB","UC_NONE"},
    /*14*/{"RFHAIL","Reflectivity of Hail","dB","UC_NONE"},
    /*15*/{"HSR","Hybrid Scan Reflectivity","dB","UC_NONE"},
    /*16*/{"HSRHT","Hybrid Scan Reflectivity Height","m","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_16[6] = {
    /*0*/{"REFZR","Equivalent radar reflectivity for rain","mm^6/m^3","UC_NONE"},
    /*1*/{"REFZI","Equivalent radar reflectivity for snow","mm^6/m^3","UC_NONE"},
    /*2*/{"REFZC","Equivalent radar reflectivity for parameterized convection","mm^6/m^3","UC_NONE"},
    /*3*/{"RETOP","Echo Top","m","UC_NONE"},
    /*4*/{"REFD","Reflectivity","dB","UC_NONE"},
    /*5*/{"REFC","Composity reflectivity","dB","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_17[2] = {
    /*0*/{"LTNGSD","Lightning Strike Density","m^2/s","UC_NONE"},
    /*1*/{"LTPINX","Lightning Potential Index (LPI) (see Note)","J/kg","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_18[19] = {
    /*0*/{"ACCES","Air concentration of Caesium 137","Bq/(m^3)","UC_NONE"},
    /*1*/{"ACIOD","Air concentration of Iodine 131","Bq/(m^3)","UC_NONE"},
    /*2*/{"ACRADP","Air concentration of radioactive pollutant","Bq/(m^3)","UC_NONE"},
    /*3*/{"GDCES","Ground deposition of Caesium 137","Bq/(m^2)","UC_NONE"},
    /*4*/{"GDIOD","Ground deposition of Iodine 131","Bq/(m^2)","UC_NONE"},
    /*5*/{"GDRADP","Ground deposition of radioactive pollutant","Bq/(m^2)","UC_NONE"},
    /*6*/{"TIACCP","Time-integrated air concentration of caesium pollutant","(Bq s)/(m^3)","UC_NONE"},
    /*7*/{"TIACIP","Time-integrated air concentration of iodine pollutant","(Bq s)/(m^3)","UC_NONE"},
    /*8*/{"TIACRP","Time-integrated air concentration of radioactive pollutant","(Bq s)/(m^3)","UC_NONE"},
    /*9*/{"","Reserved","-","UC_NONE"},
    /*10*/{"AIRCON","Air Concentration","Bq/(m^3)","UC_NONE"},
    /*11*/{"WETDEP","Wet Deposition","Bq/(m^2)","UC_NONE"},
    /*12*/{"DRYDEP","Dry Deposition","Bq/(m^2)","UC_NONE"},
    /*13*/{"TOTLWD","Total Deposition (Wet + Dry)","Bq/(m^2)","UC_NONE"},
    /*14*/{"SACON","Specific Activity Concentration","Bq/kg","UC_NONE"},
    /*15*/{"MAXACON","Maximum of Air Concentration in Layer","Bq/(m^3)","UC_NONE"},
    /*16*/{"HMXACON","Height of Maximum of Air Concentration","m","UC_NONE"},
    /*17*/{"CIAIRC","Column-Integrated Air Concentration","Bq/(m^2)","UC_NONE"},
    /*18*/{"CAACL","Column-Averaged Air Concentration in Layer","Bq/(m^3)","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_19[36] = {
    /*0*/{"VIS","Visibility","m","UC_M2StatuteMile"},
    /*1*/{"ALBDO","Albedo","%","UC_NONE"},
    /*2*/{"TSTM","Thunderstorm probability","%","UC_NONE"},
    /*3*/{"MIXHT","Mixed layer depth","m","UC_NONE"},
    /*4*/{"VOLASH","Volcanic ash","0=not present; 1=present; 255=missing","UC_NONE"},
    /*5*/{"ICIT","Icing top","m","UC_NONE"},
    /*6*/{"ICIB","Icing base","m","UC_NONE"},
    /*7*/{"ICI","Icing","0=None; 1=Light; 2=Moderate; 3=Severe; 255=missing","UC_NONE"},
    /*8*/{"TURBT","Turbulance top","m","UC_NONE"},
    /*9*/{"TURBB","Turbulence base","m","UC_NONE"},
    /*10*/{"TURB","Turbulance","0=None(smooth); 1=Light; 2=Moderate; 3=Severe; 4=Extreme; 255=missing","UC_NONE"},
    /*11*/{"TKE","Turbulent kinetic energy","J/kg","UC_NONE"},
    /*12*/{"PBLREG","Planetary boundary layer regime","0=Reserved; 1=Stable; 2=Mechanically driven turbulence; 3=Forced convection; 4=Free convection; 255=missing","UC_NONE"},
    /*13*/{"CONTI","Contrail intensity","0=Contrail not present; 1=Contrail present; 255=missing","UC_NONE"},
    /*14*/{"CONTET","Contrail engine type","0=Low bypass; 1=High bypass; 2=Non bypass; 255=missing","UC_NONE"},
    /*15*/{"CONTT","Contrail top","m","UC_NONE"},
    /*16*/{"CONTB","Contrail base","m","UC_NONE"},
    /*17*/{"MXSALB","Maximum snow albedo","%","UC_NONE"},
    /*18*/{"SNFALB","Snow free albedo","%","UC_NONE"},
    /*19*/{"SALBD","Snow albedo","%","UC_NONE"},
    /*20*/{"ICIP","Icing","%","UC_NONE"},
    /*21*/{"CTP","In-Cloud Turbulence","%","UC_NONE"},
    /*22*/{"CAT","Clear Air Turbulence","%","UC_NONE"},
    /*23*/{"SLDP","Supercooled Large Droplet Probability","%","UC_NONE"},
    /*24*/{"CONTKE","Convective Turbulent Kinetic Energy","J/kg","UC_NONE"},
    /*25*/{"WIWW","Weather Interpretation ww (WMO)"," ","UC_NONE"},
    /*26*/{"CONVO","Convective Outlook","0=No Risk Area; 1=Reserved; 2=General Thunderstorm Risk Area; 3=Reserved; 4=Slight Risk Area; 5=Reserved; 6=Moderate Risk Area;  7=Reserved; 8=High Risk Area; 9-10=Reserved; 11=Dry Thunderstorm (Dry Lightning) Risk Area; 12-13=Reserved; 14=Critical Risk Area; 15-17=Reserved18=Extremely Critical Risk Area; 255=missing","UC_NONE"},
    /*27*/{"ICESC","Icing Scenario", "0=None; 1=General, 2=Convective 3=Stratiform; 4=Freezing; 5-191=Reserved; 255=missing","UC_NONE"},
    /*28*/{"MWTURB","Mountain Wave Turbulence (Eddy Dissipation Rate)","m^(2/3)/s","UC_NONE"},
    /*29*/{"CATEDR","Clear Air Turbulence (CAT) (Eddy Dissipation Rate)","m^(2/3)/s","UC_NONE"},
    /*30*/{"EDPARM","Eddy Dissipation Parameter","m^(2/3)/s","UC_NONE"},
    /*31*/{"MXEDPRM","Maximum of Eddy Dissipation Parameter in Layer","m^(2/3)/s","UC_NONE"},
    /*32*/{"HIFREL","Highest Freezing Level","m","UC_NONE"},
    /*33*/{"VISLFOG","Visibility Through Liquid Fog","m","UC_NONE"},
    /*34*/{"VISIFOG","Visibility Through Ice Fog","m","UC_NONE"},
    /*35*/{"VISBSN","Visibility Through Blowing Snow","m","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_190[1] = {
    /*0*/{"","Arbitrary text string","CCITTIA5","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_191[4] = {
    /*0*/{"TSEC","Seconds prior to initial reference time (defined in Section 1)","s","UC_NONE"},
    /*1*/{"GEOLAT","Geographical Latitude","deg N","UC_NONE"},
    /*2*/{"GEOLON","Geographical Longitude","deg E","UC_NONE"},
    /*3*/{"DSLOBS","Days Since Last Observation","d","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_2[47] = {
    /*0*/{"WDIR","Wind direction (from which blowing)","deg true","UC_NONE"},
    /*1*/{"WIND","Wind speed","m/s","UC_MS2Knots"},
    /*2*/{"UGRD","u-component of wind","m/s","UC_NONE"},
    /*3*/{"VGRD","v-component of wind","m/s","UC_NONE"},
    /*4*/{"STRM","Stream function","(m^2)/s","UC_NONE"},
    /*5*/{"VPOT","Velocity potential","(m^2)/s","UC_NONE"},
    /*6*/{"MNTSF","Montgomery stream function","(m^2)/(s^2)","UC_NONE"},
    /*7*/{"SGCVV","Sigma coordinate vertical velocity","1/s","UC_NONE"},
    /*8*/{"VVEL","Vertical velocity (pressure)","Pa/s","UC_NONE"},
    /*9*/{"DZDT","Vertical velocity (geometric)","m/s","UC_NONE"},
    /*10*/{"ABSV","Absolute vorticity","1/s","UC_NONE"},
    /*11*/{"ABSD","Absolute divergence","1/s","UC_NONE"},
    /*12*/{"RELV","Relative vorticity","1/s","UC_NONE"},
    /*13*/{"RELD","Relative divergence","1/s","UC_NONE"},
    /*14*/{"PVORT","Potential vorticity","K(m^2)/(kg s)","UC_NONE"},
    /*15*/{"VUCSH","Vertical u-component shear","1/s","UC_NONE"},
    /*16*/{"VVCSH","Vertical v-component shear","1/s","UC_NONE"},
    /*17*/{"UFLX","Momentum flux; u component","N/(m^2)","UC_NONE"},
    /*18*/{"VFLX","Momentum flux; v component","N/(m^2)","UC_NONE"},
    /*19*/{"WMIXE","Wind mixing energy","J","UC_NONE"},
    /*20*/{"BLYDP","Boundary layer dissipation","W/(m^2)","UC_NONE"},
    /*21*/{"MAXGUST","Maximum wind speed","m/s","UC_NONE"},
    /*22*/{"GUST","Wind speed (gust)","m/s","UC_MS2Knots"},
    /*23*/{"UGUST","u-component of wind (gust)","m/s","UC_NONE"},
    /*24*/{"VGUST","v-component of wind (gust)","m/s","UC_NONE"},
    /*25*/{"VWSH","Vertical speed shear","1/s","UC_NONE"},
    /*26*/{"MFLX","Horizontal momentum flux","N/(m^2)","UC_NONE"},
    /*27*/{"USTM","U-component storm motion","m/s","UC_NONE"},
    /*28*/{"VSTM","V-component storm motion","m/s","UC_NONE"},
    /*29*/{"CD","Drag coefficient","-","UC_NONE"},
    /*30*/{"FRICV","Frictional velocity","m/s","UC_NONE"},
    /*31*/{"TDCMOM","Turbulent Diffusion Coefficient for Momentum","(m^2)/s","UC_NONE"},
    /*32*/{"ETACVV","Eta Coordinate Vertical Velocity","1/s","UC_NONE"},
    /*33*/{"WINDF","Wind Fetch","m","UC_NONE"},
    /*34*/{"NWIND","Normal Wind Component","m/s","UC_NONE"},
    /*35*/{"TWIND","Tangential Wind Component","m/s","UC_NONE"},
    /*36*/{"AFRWE","Amplitude Function for Rossby Wave Envelope for Meridional Wind","m/s","UC_NONE"},
    /*37*/{"NTSS","Northward Turbulent Surface Stress","1/(m^2)","UC_NONE"},
    /*38*/{"ETSS","Eastward Turbulent Surface Stress","1/(m^2)","UC_NONE"},
    /*39*/{"EWTPARM","Eastward Wind Tendency Due to Parameterizations","m/(s^2)","UC_NONE"},
    /*40*/{"NWTPARM","Northward Wind Tendency Due to Parameterizations","m/(s^2)","UC_NONE"},
    /*41*/{"UGWIND","U-Component of Geostrophic Wind","m/s","UC_NONE"},
    /*42*/{"VGWIND","V-Component of Geostrophic Wind","m/s","UC_NONE"},
    /*43*/{"GEOWD","Geostrophic Wind Direction","deg true","UC_NONE"},
    /*44*/{"GEOWS","Geostrophic Wind Speed","m/s","UC_NONE"},
    /*45*/{"UNDIV","Unbalanced Component of Divergence","1/s","UC_NONE"},
    /*46*/{"VORTADV","Vorticity Advection","1/(s^2)","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_20[131] = {
    /*0*/{"MASSDEN","Mass Density (Concentration)","kg/(m^3)","UC_NONE"},
    /*1*/{"COLMD","Column-Integrated Mass Density","kg/(m^2)","UC_NONE"},
    /*2*/{"MASSMR","Mass Mixing Ratio (Mass Fraction in Air)","kg/kg","UC_NONE"},
    /*3*/{"AEMFLX","Atmosphere Emission Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*4*/{"ANPMFLX","Atmosphere Net Production Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*5*/{"ANPEMFLX","Atmosphere Net Production and Emission Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*6*/{"SDDMFLX","Surface Dry Deposition Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*7*/{"SWDMFLX","Surface Wet Deposition Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*8*/{"AREMFLX","Atmosphere Re-Emission Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*9*/{"WLSMFLX","Wet Deposition by Large-Scale Precipitation Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*10*/{"WDCPMFLX","Wet Deposition by Convective Precipitation Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*11*/{"SEDMFLX","Sedimentation Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*12*/{"DDMFLX","Dry Deposition Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*13*/{"TRANHH","Transfer From Hydrophobic to Hydrophilic","kg(kg*s)","UC_NONE"},
    /*14*/{"TRSDS","Transfer From SO2 (Sulphur Dioxide) to SO4 (Sulphate)","kg(kg*s)","UC_NONE"},
    /*15*/{"DDVEL","Dry deposition velocity","m/s","UC_NONE"},
    /*16*/{"MSSRDRYA","Mass mixing ratio with respect to dry air","kg/kg","UC_NONE"},
    /*17*/{"MSSRWETA","Mass mixing ratio with respect to wet air","kg/kg","UC_NONE"},
    /*18*/{"","Reserved","-","UC_NONE"},
    /*19*/{"","Reserved","-","UC_NONE"},
    /*20*/{"","Reserved","-","UC_NONE"},
    /*21*/{"","Reserved","-","UC_NONE"},
    /*22*/{"","Reserved","-","UC_NONE"},
    /*23*/{"","Reserved","-","UC_NONE"},
    /*24*/{"","Reserved","-","UC_NONE"},
    /*25*/{"","Reserved","-","UC_NONE"},
    /*26*/{"","Reserved","-","UC_NONE"},
    /*27*/{"","Reserved","-","UC_NONE"},
    /*28*/{"","Reserved","-","UC_NONE"},
    /*29*/{"","Reserved","-","UC_NONE"},
    /*30*/{"","Reserved","-","UC_NONE"},
    /*31*/{"","Reserved","-","UC_NONE"},
    /*32*/{"","Reserved","-","UC_NONE"},
    /*33*/{"","Reserved","-","UC_NONE"},
    /*34*/{"","Reserved","-","UC_NONE"},
    /*35*/{"","Reserved","-","UC_NONE"},
    /*36*/{"","Reserved","-","UC_NONE"},
    /*37*/{"","Reserved","-","UC_NONE"},
    /*38*/{"","Reserved","-","UC_NONE"},
    /*39*/{"","Reserved","-","UC_NONE"},
    /*40*/{"","Reserved","-","UC_NONE"},
    /*41*/{"","Reserved","-","UC_NONE"},
    /*42*/{"","Reserved","-","UC_NONE"},
    /*43*/{"","Reserved","-","UC_NONE"},
    /*44*/{"","Reserved","-","UC_NONE"},
    /*45*/{"","Reserved","-","UC_NONE"},
    /*46*/{"","Reserved","-","UC_NONE"},
    /*47*/{"","Reserved","-","UC_NONE"},
    /*48*/{"","Reserved","-","UC_NONE"},
    /*49*/{"","Reserved","-","UC_NONE"},
    /*50*/{"AIA","Amount in Atmosphere","mol","UC_NONE"},
    /*51*/{"CONAIR","Concentration in Air","mol/(m^3)","UC_NONE"},
    /*52*/{"VMXR","Volume Mixing Ratio (Fraction in Air)","mol/mol","UC_NONE"},
    /*53*/{"CGPRC","Chemical Gross Production Rate of Concentration","mol/(m^3*s)","UC_NONE"},
    /*54*/{"CGDRC","Chemical Gross Destruction Rate of Concentration","mol/(m^3*s)","UC_NONE"},
    /*55*/{"SFLUX","Surface Flux","mol/(m^2*s)","UC_NONE"},
    /*56*/{"COAIA","Changes of Amount in Atmosphere","mol/s","UC_NONE"},
    /*57*/{"TYABA","Total Yearly Average Burden of the Atmosphere","mol","UC_NONE"},
    /*58*/{"TYAAL","Total Yearly Average Atmospheric Loss","mol/s","UC_NONE"},
    /*59*/{"ANCON","Aerosol Number Concentration","1/(m^3)","UC_NONE"},
    /*60*/{"ASNCON","Aerosol Specific Number Concentration","1/kg","UC_NONE"},
    /*61*/{"MXMASSD","Maximum of Mass Density","kg(/m^3)","UC_NONE"},
    /*62*/{"HGTMD","Height of Mass Density","m","UC_NONE"},
    /*63*/{"CAVEMDL","Column-Averaged Mass Density in Layer","kg/(m^3)","UC_NONE"},
    /*64*/{"MOLRDRYA","Mole fraction with respect to dry air","mol/mol","UC_NONE"},
    /*65*/{"MOLRWETA","Mole fraction with respect to dry air","mol/mol","UC_NONE"},
    /*66*/{"CINCLDSP","Column-integrated in-cloud scavenging rate by precipitation","kg/(m^2 s)","UC_NONE"},
    /*67*/{"CBLCLDSP","Column-integrated below-cloud scavenging rate by precipitation","kg/(m^2 s)","UC_NONE"},
    /*68*/{"CIRELREP","Column-integrated release rate from evaporating precipitation","kg/(m^2 s)","UC_NONE"},
    /*69*/{"CINCSLSP","Column-integrated in-cloud scavenging rate by large-scale precipitation","kg/(m^2 s)","UC_NONE"},
    /*70*/{"CBECSLSP","Column-integrated below-cloud scavenging rate by large-scale precipitation","kg/(m^2 s)","UC_NONE"},
    /*71*/{"CRERELSP","Column-integrated release rate from evaporating large-scale precipitation","kg/(m^2 s)-","UC_NONE"},
    /*72*/{"CINCSRCP","Column-integrated in-cloud scavenging rate by convective precipitation","kg/(m^2 s)","UC_NONE"},
    /*73*/{"CBLCSRCP","Column-integrated below-cloud scavenging rate by convective precipitation","kg/(m^2 s)","UC_NONE"},
    /*74*/{"CIRERECP","Column-integrated release rate from evaporating convective precipitation","kg/(m^2 s)","UC_NONE"},
    /*75*/{"WFIREFLX","Wildfire flux","kg/(m^2 s)","UC_NONE"},
    /*76*/{"","Reserved","-","UC_NONE"},
    /*77*/{"","Reserved","-","UC_NONE"},
    /*78*/{"","Reserved","-","UC_NONE"},
    /*79*/{"","Reserved","-","UC_NONE"},
    /*80*/{"","Reserved","-","UC_NONE"},
    /*81*/{"","Reserved","-","UC_NONE"},
    /*82*/{"","Reserved","-","UC_NONE"},
    /*83*/{"","Reserved","-","UC_NONE"},
    /*84*/{"","Reserved","-","UC_NONE"},
    /*85*/{"","Reserved","-","UC_NONE"},
    /*86*/{"","Reserved","-","UC_NONE"},
    /*87*/{"","Reserved","-","UC_NONE"},
    /*88*/{"","Reserved","-","UC_NONE"},
    /*89*/{"","Reserved","-","UC_NONE"},
    /*90*/{"","Reserved","-","UC_NONE"},
    /*91*/{"","Reserved","-","UC_NONE"},
    /*92*/{"","Reserved","-","UC_NONE"},
    /*93*/{"","Reserved","-","UC_NONE"},
    /*94*/{"","Reserved","-","UC_NONE"},
    /*95*/{"","Reserved","-","UC_NONE"},
    /*96*/{"","Reserved","-","UC_NONE"},
    /*97*/{"","Reserved","-","UC_NONE"},
    /*98*/{"","Reserved","-","UC_NONE"},
    /*99*/{"","Reserved","-","UC_NONE"},
    /*100*/{"SADEN","Surface Area Density (Aerosol)","1/m","UC_NONE"},
    /*101*/{"ATMTK","Vertical Visual Range","m","UC_NONE"},
    /*102*/{"AOTK","Atmosphere Optical Thickness","Numeric","UC_NONE"},
    /*103*/{"SSALBK","Single Scattering Albedo","Numeric","UC_NONE"},
    /*104*/{"ASYSFK","Asymmetry Factor","Numeric","UC_NONE"},
    /*105*/{"AECOEF","Aerosol Extinction Coefficient","1/m","UC_NONE"},
    /*106*/{"AACOEF","Aerosol Absorption Coefficient","1/m","UC_NONE"},
    /*107*/{"ALBSAT","Aerosol Lidar Backscatter from Satellite","1/(m*sr)","UC_NONE"},
    /*108*/{"ALBGRD","Aerosol Lidar Backscatter from the Ground","1/(m*sr)","UC_NONE"},
    /*109*/{"ALESAT","Aerosol Lidar Extinction from Satellite","1/m","UC_NONE"},
    /*110*/{"ALEGRD","Aerosol Lidar Extinction from the Ground","1/m","UC_NONE"},
    /*111*/{"ANGSTEXP","Angstrom Exponent","Numeric","UC_NONE"},
    /*112*/{"SCTAOTK","Scattering Aerosol Optical Thickness","Numeric","UC_NONE"},
    /*113*/{"","Reserved","-","UC_NONE"},
    /*114*/{"","Reserved","-","UC_NONE"},
    /*115*/{"","Reserved","-","UC_NONE"},
    /*116*/{"","Reserved","-","UC_NONE"},
    /*117*/{"","Reserved","-","UC_NONE"},
    /*118*/{"","Reserved","-","UC_NONE"},
    /*119*/{"","Reserved","-","UC_NONE"},
    /*120*/{"","Reserved","-","UC_NONE"},
    /*121*/{"","Reserved","-","UC_NONE"},
    /*122*/{"","Reserved","-","UC_NONE"},
    /*123*/{"","Reserved","-","UC_NONE"},
    /*124*/{"","Reserved","-","UC_NONE"},
    /*125*/{"","Reserved","-","UC_NONE"},
    /*126*/{"","Reserved","-","UC_NONE"},
    /*127*/{"","Reserved","-","UC_NONE"},
    /*128*/{"","Reserved","-","UC_NONE"},
    /*129*/{"","Reserved","-","UC_NONE"},
    /*130*/{"","Reserved","-","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_253[1] = {
    /*0*/{"","Arbitrary text string","CCITTIA5","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_3[32] = {
    /*0*/{"PRES","Pressure","Pa","UC_NONE"},
    /*1*/{"PRMSL","Pressure reduced to MSL","Pa","UC_NONE"},
    /*2*/{"PTEND","Pressure tendency","Pa/s","UC_NONE"},
    /*3*/{"ICAHT","ICAO Standard Atmosphere Reference Height","m","UC_NONE"},
    /*4*/{"GP","Geopotential","(m^2)/(s^2)","UC_NONE"},
    /*5*/{"HGT","Geopotential height","gpm","UC_NONE"},
    /*6*/{"DIST","Geometric height","m","UC_M2Feet"},
    /*7*/{"HSTDV","Standard deviation of height","m","UC_NONE"},
    /*8*/{"PRESA","Pressure anomaly","Pa","UC_NONE"},
    /*9*/{"GPA","Geopotential height anomaly","gpm","UC_NONE"},
    /*10*/{"DEN","Density","kg/(m^3)","UC_NONE"},
    /*11*/{"ALTS","Altimeter setting","Pa","UC_NONE"},
    /*12*/{"THICK","Thickness","m","UC_NONE"},
    /*13*/{"PRESALT","Pressure altitude","m","UC_NONE"},
    /*14*/{"DENALT","Density altitude","m","UC_NONE"},
    /*15*/{"5WAVH","5-wave geopotential height","gpm","UC_NONE"},
    /*16*/{"U-GWD","Zonal flux of gravity wave stress","N/(m^2)","UC_NONE"},
    /*17*/{"V-GWD","Meridional flux of gravity wave stress","N/(m^2)","UC_NONE"},
    /*18*/{"HPBL","Planetary boundary layer height","m","UC_NONE"},
    /*19*/{"5WAVA","5-wave geopotential height anomaly","gpm","UC_NONE"},
    /*20*/{"SDSGSO","Standard deviation of sub-grid scale orography","m","UC_NONE"},
    /*21*/{"AOSGSO","Angle of sub-gridscale orography","rad","UC_NONE"},
    /*22*/{"SSGSO","Slope of sub-gridscale orography","Numeric","UC_NONE"},
    /*23*/{"GSGSO","Gravity wave dissipation","W/m^2","UC_NONE"},
    /*24*/{"ASGSO","Anisotrophy of sub-gridscale orography","Numeric","UC_NONE"},
    /*25*/{"NLPRES","Natural Logarithm of Pressure in Pa","Numeric","UC_NONE"},
    /*26*/{"EXPRES","Exner Pressure","Numeric","UC_NONE"},
    /*27*/{"UMFLX","Updraught Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*28*/{"DMFLX","Downdraught Mass Flux","kg/(m^2*s)","UC_NONE"},
    /*29*/{"UDRATE","Updraught Detrainment Rate","kg/(m^3*s)","UC_NONE"},
    /*30*/{"DDRATE","Downdraught Detrainment Rate","kg/(m^3*s)","UC_NONE"},
    /*31*/{"UCLSPRS","Unbalanced Component of Logarithm of Surface Pressure","","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_4[54] = {
    /*0*/{"NSWRS","Net short-wave radiation flux (surface)","W/(m^2)","UC_NONE"},
    /*1*/{"NSWRT","Net short-wave radiation flux (top of atmosphere)","W/(m^2)","UC_NONE"},
    /*2*/{"SWAVR","Short wave radiation flux","W/(m^2)","UC_NONE"},
    /*3*/{"GRAD","Global radiation flux","W/(m^2)","UC_NONE"},
    /*4*/{"BRTMP","Brightness temperature","K","UC_NONE"},
    /*5*/{"LWRAD","Radiance (with respect to wave number)","W/(m sr)","UC_NONE"},
    /*6*/{"SWRAD","Radiance (with respect to wave length)","W/(m^3 sr)","UC_NONE"},
    /*7*/{"DSWRF","Downward short-wave radiation flux","W/(m^2)","UC_NONE"},
    /*8*/{"USWRF","Upward short-wave radiation flux","W/(m^2)","UC_NONE"},
    /*9*/{"NSWRF","Net short wave radiation flux","W/(m^2)","UC_NONE"},
    /*10*/{"PHOTAR","Photosynthetically active radiation","W/(m^2)","UC_NONE"},
    /*11*/{"NSWRFCS","Net short-wave radiation flux; clear sky","W/(m^2)","UC_NONE"},
    /*12*/{"DWUVR","Downward UV radiation","W/(m^2)","UC_NONE"},
    /*13*/{"DSWRFLX","Direct Short Wave Radiation Flux","W/(m^2)","UC_NONE"},
    /*14*/{"DIFSWRF","Diffuse Short Wave Radiation Flux","W/(m^2)","UC_NONE"},
    /*15*/{"","Reserved","-","UC_NONE"},
    /*16*/{"","Reserved","-","UC_NONE"},
    /*17*/{"","Reserved","-","UC_NONE"},
    /*18*/{"","Reserved","-","UC_NONE"},
    /*19*/{"","Reserved","-","UC_NONE"},
    /*20*/{"","Reserved","-","UC_NONE"},
    /*21*/{"","Reserved","-","UC_NONE"},
    /*22*/{"","Reserved","-","UC_NONE"},
    /*23*/{"","Reserved","-","UC_NONE"},
    /*24*/{"","Reserved","-","UC_NONE"},
    /*25*/{"","Reserved","-","UC_NONE"},
    /*26*/{"","Reserved","-","UC_NONE"},
    /*27*/{"","Reserved","-","UC_NONE"},
    /*28*/{"","Reserved","-","UC_NONE"},
    /*29*/{"","Reserved","-","UC_NONE"},
    /*30*/{"","Reserved","-","UC_NONE"},
    /*31*/{"","Reserved","-","UC_NONE"},
    /*32*/{"","Reserved","-","UC_NONE"},
    /*33*/{"","Reserved","-","UC_NONE"},
    /*34*/{"","Reserved","-","UC_NONE"},
    /*35*/{"","Reserved","-","UC_NONE"},
    /*36*/{"","Reserved","-","UC_NONE"},
    /*37*/{"","Reserved","-","UC_NONE"},
    /*38*/{"","Reserved","-","UC_NONE"},
    /*39*/{"","Reserved","-","UC_NONE"},
    /*40*/{"","Reserved","-","UC_NONE"},
    /*41*/{"","Reserved","-","UC_NONE"},
    /*42*/{"","Reserved","-","UC_NONE"},
    /*43*/{"","Reserved","-","UC_NONE"},
    /*44*/{"","Reserved","-","UC_NONE"},
    /*45*/{"","Reserved","-","UC_NONE"},
    /*46*/{"","Reserved","-","UC_NONE"},
    /*47*/{"","Reserved","-","UC_NONE"},
    /*48*/{"","Reserved","-","UC_NONE"},
    /*49*/{"","Reserved","-","UC_NONE"},
    /*50*/{"UVIUCS","UV index (under clear sky)","Numeric","UC_NONE"},
    /*51*/{"UVI","UV index","W/(m^2)","UC_UVIndex"},
    /*52*/{"DSWRFCS","Downward Short-Wave Radiation Flux,  Clear Sky","W/(m^2)","UC_NONE"},
    /*53*/{"USWRFCS","Upward Short-Wave Radiation Flux,  Clear Sky","W/(m^2)","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_5[9] = {
    /*0*/{"NLWRS","Net long wave radiation flux (surface)","W/(m^2)","UC_NONE"},
    /*1*/{"NLWRT","Net long wave radiation flux (top of atmosphere)","W/(m^2)","UC_NONE"},
    /*2*/{"LWAVR","Long wave radiation flux","W/(m^2)","UC_NONE"},
    /*3*/{"DLWRF","Downward long-wave radiation flux","W/(m^2)","UC_NONE"},
    /*4*/{"ULWRF","Upward long-wave radiation flux","W/(m^2)","UC_NONE"},
    /*5*/{"NLWRF","Net long wave radiation flux","W/(m^2)","UC_NONE"},
    /*6*/{"NLWRCS","Net long-wave radiation flux; clear sky","W/(m^2)","UC_NONE"},
    /*7*/{"BRTEMP","Brightness Temperature","K","UC_K2F"},
    /*8*/{"DLWRFCS","Downward Long-Wave Radiation Flux,  Clear Sky","W/(m^2)","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_6[50] = {
    /*0*/{"CICE","Cloud Ice","kg/(m^2)","UC_NONE"},
    /*1*/{"TCDC","Total cloud cover","%","UC_NONE"},
    /*2*/{"CDCON","Convective cloud cover","%","UC_NONE"},
    /*3*/{"LCDC","Low cloud cover","%","UC_NONE"},
    /*4*/{"MCDC","Medium cloud cover","%","UC_NONE"},
    /*5*/{"HCDC","High cloud cover","%","UC_NONE"},
    /*6*/{"CWAT","Cloud water","kg/(m^2)","UC_NONE"},
    /*7*/{"CDCA","Cloud amount","%","UC_NONE"},
    /*8*/{"CDCT","Cloud type","0=clear; 1=Cumulonimbus; 2=Stratus; 3=Stratocumulus; 4=Cumulus; 5=Altostratus; 6=Nimbostratus; 7=Altocumulus; 8=Cirrostratus; 9=Cirrocumulus; 10=Cirrus; 11=Cumulonimbus (fog); 12=Stratus (fog); 13=Stratocumulus (fog); 14=Cumulus (fog); 15=Altostratus (fog); 16=Nimbostratus (fog); 17=Altocumulus (fog); 18=Cirrostratus (fog); 19=Cirrocumulus (fog); 20=Cirrus (fog); 191=unknown; 255=missing","UC_NONE"},
    /*9*/{"TMAXT","Thunderstorm maximum tops","m","UC_NONE"},
    /*10*/{"THUNC","Thunderstorm coverage","0=none; 1=isolated (1%-2%); 2=few (3%-15%); 3=scattered (16%-45%); 4=numerous (> 45%); 255=missing","UC_NONE"},
    /*11*/{"CDCB","Cloud base","m","UC_M2Feet"},
    /*12*/{"CDCT","Cloud top","m","UC_M2Feet"},
    /*13*/{"CEIL","Ceiling","m","UC_M2Feet"},
    /*14*/{"CDLYR","Non-convective cloud cover","%","UC_NONE"},
    /*15*/{"CWORK","Cloud work function","J/kg","UC_NONE"},
    /*16*/{"CUEFI","Convective cloud efficiency","-","UC_NONE"},
    /*17*/{"TCOND","Total condensate","kg/kg","UC_NONE"},
    /*18*/{"TCOLW","Total column-integrated cloud water","kg/(m^2)","UC_NONE"},
    /*19*/{"TCOLI","Total column-integrated cloud ice","kg/(m^2)","UC_NONE"},
    /*20*/{"TCOLC","Total column-integrated condensate","kg/(m^2)","UC_NONE"},
    /*21*/{"FICE","Ice fraction of total condensate","-","UC_NONE"},
    /*22*/{"CDCC","Cloud cover","%","UC_NONE"},
    /*23*/{"CDCIMR","Cloud ice mixing ratio","kg/kg","UC_NONE"},
    /*24*/{"SUNS","Sunshine","Numeric","UC_NONE"},
    /*25*/{"CBHE","Horizontal extent of cumulonimbus (CB)","%","UC_NONE"},
    /*26*/{"HCONCB","Height of Convective Cloud Base","m","UC_NONE"},
    /*27*/{"HCONCT","Height of Convective Cloud Top","m","UC_NONE"},
    /*28*/{"NCONCD","Number Concentration of Cloud Droplets","1/kg","UC_NONE"},
    /*29*/{"NCCICE","Number Concentration of Cloud Ice","1/kg","UC_NONE"},
    /*30*/{"NDENCD","Number Density of Cloud Droplets","1/(m^3)","UC_NONE"},
    /*31*/{"NDCICE","Number Density of Cloud Ice","1/(m^3)","UC_NONE"},
    /*32*/{"FRACCC","Fraction of Cloud Cover","Numeric","UC_NONE"},
    /*33*/{"SUNSD","SunShine Duration","s","UC_NONE"},
    /*34*/{"SLWTC","Surface Long Wave Effective Total Cloudiness","Numeric","UC_NONE"},
    /*35*/{"SSWTC","Surface Short Wave Effective Total Cloudiness","Numeric","UC_NONE"},
    /*36*/{"FSTRPC","Fraction of Stratiform Precipitation Cover","Proportion","UC_NONE"},
    /*37*/{"FCONPC","Fraction of Convective Precipitation Cover","Proportion","UC_NONE"},
    /*38*/{"MASSDCD","Mass Density of Cloud Droplets","kg/(m^3)","UC_NONE"},
    /*39*/{"MASSDCI","Mass Density of Cloud Ice","kg/(m^3)","UC_NONE"},
    /*40*/{"MDCCWD","Mass Density of Convective Cloud Water Droplets","kg/(m^3)","UC_NONE"},
    /*41*/{"","Reserved","-","UC_NONE"},
    /*42*/{"","Reserved","-","UC_NONE"},
    /*43*/{"","Reserved","-","UC_NONE"},
    /*44*/{"","Reserved","-","UC_NONE"},
    /*45*/{"","Reserved","-","UC_NONE"},
    /*46*/{"","Reserved","-","UC_NONE"},
    /*47*/{"VFRCWD","Volume Fraction of Cloud Water Droplets","Numeric","UC_NONE"},
    /*48*/{"VFRCICE","Volume Fraction of Cloud Ice Particles","Numeric","UC_NONE"},
    /*49*/{"VFRCIW","Volume Fraction of Cloud (Ice and/or Water)","Numeric","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_0_7[201] = {
    /*0*/{"PLI","Parcel lifted index (to 500 hPa)","K","UC_NONE"},
    /*1*/{"BLI","Best lifted index (to 500 hPa)","K","UC_NONE"},
    /*2*/{"KX","K index","K","UC_NONE"},
    /*3*/{"KOX","KO index","K","UC_NONE"},
    /*4*/{"TOTALX","Total totals index","K","UC_NONE"},
    /*5*/{"SX","Sweat index","numeric","UC_NONE"},
    /*6*/{"CAPE","Convective available potential energy","J/kg","UC_NONE"},
    /*7*/{"CIN","Convective inhibition","J/kg","UC_NONE"},
    /*8*/{"HLCY","Storm relative helicity","J/kg","UC_NONE"},
    /*9*/{"EHLX","Energy helicity index","numeric","UC_NONE"},
    /*10*/{"LFTX","Surface lifted index","K","UC_NONE"},
    /*11*/{"4LFTX","Best (4-layer) lifted index","K","UC_NONE"},
    /*12*/{"RI","Richardson number","-","UC_NONE"},
    /*13*/{"SHWINX","Showalter Index","K","UC_NONE"},
    /*14*/{"","Reserved","-","UC_NONE"},
    /*15*/{"UPHL","Updraft Helicity","m^2/s^2","UC_NONE"},
    /*16*/{"BLKRN","Bulk Richardson Number","-","UC_NONE"},
    /*17*/{"GRDRN","Gradient Richardson Number","-","UC_NONE"},
    /*18*/{"FLXRN","Flux Richardson Number","-","UC_NONE"},
    /*19*/{"CONAPES","Convective Available Potential Energy Shear","m^2/s^2","UC_NONE"},
    /*20*/{"-","Reserved","-","UC_NONE"},
    /*21*/{"-","Reserved","-","UC_NONE"},
    /*22*/{"-","Reserved","-","UC_NONE"},
    /*23*/{"-","Reserved","-","UC_NONE"},
    /*24*/{"-","Reserved","-","UC_NONE"},
    /*25*/{"-","Reserved","-","UC_NONE"},
    /*26*/{"-","Reserved","-","UC_NONE"},
    /*27*/{"-","Reserved","-","UC_NONE"},
    /*28*/{"-","Reserved","-","UC_NONE"},
    /*29*/{"-","Reserved","-","UC_NONE"},
    /*30*/{"-","Reserved","-","UC_NONE"},
    /*31*/{"-","Reserved","-","UC_NONE"},
    /*32*/{"-","Reserved","-","UC_NONE"},
    /*33*/{"-","Reserved","-","UC_NONE"},
    /*34*/{"-","Reserved","-","UC_NONE"},
    /*35*/{"-","Reserved","-","UC_NONE"},
    /*36*/{"-","Reserved","-","UC_NONE"},
    /*37*/{"-","Reserved","-","UC_NONE"},
    /*38*/{"-","Reserved","-","UC_NONE"},
    /*39*/{"-","Reserved","-","UC_NONE"},
    /*40*/{"-","Reserved","-","UC_NONE"},
    /*41*/{"-","Reserved","-","UC_NONE"},
    /*42*/{"-","Reserved","-","UC_NONE"},
    /*43*/{"-","Reserved","-","UC_NONE"},
    /*44*/{"-","Reserved","-","UC_NONE"},
    /*45*/{"-","Reserved","-","UC_NONE"},
    /*46*/{"-","Reserved","-","UC_NONE"},
    /*47*/{"-","Reserved","-","UC_NONE"},
    /*48*/{"-","Reserved","-","UC_NONE"},
    /*49*/{"-","Reserved","-","UC_NONE"},
    /*50*/{"-","Reserved","-","UC_NONE"},
    /*51*/{"-","Reserved","-","UC_NONE"},
    /*52*/{"-","Reserved","-","UC_NONE"},
    /*53*/{"-","Reserved","-","UC_NONE"},
    /*54*/{"-","Reserved","-","UC_NONE"},
    /*55*/{"-","Reserved","-","UC_NONE"},
    /*56*/{"-","Reserved","-","UC_NONE"},
    /*57*/{"-","Reserved","-","UC_NONE"},
    /*58*/{"-","Reserved","-","UC_NONE"},
    /*59*/{"-","Reserved","-","UC_NONE"},
    /*60*/{"-","Reserved","-","UC_NONE"},
    /*61*/{"-","Reserved","-","UC_NONE"},
    /*62*/{"-","Reserved","-","UC_NONE"},
    /*63*/{"-","Reserved","-","UC_NONE"},
    /*64*/{"-","Reserved","-","UC_NONE"},
    /*65*/{"-","Reserved","-","UC_NONE"},
    /*66*/{"-","Reserved","-","UC_NONE"},
    /*67*/{"-","Reserved","-","UC_NONE"},
    /*68*/{"-","Reserved","-","UC_NONE"},
    /*69*/{"-","Reserved","-","UC_NONE"},
    /*70*/{"-","Reserved","-","UC_NONE"},
    /*71*/{"-","Reserved","-","UC_NONE"},
    /*72*/{"-","Reserved","-","UC_NONE"},
    /*73*/{"-","Reserved","-","UC_NONE"},
    /*74*/{"-","Reserved","-","UC_NONE"},
    /*75*/{"-","Reserved","-","UC_NONE"},
    /*76*/{"-","Reserved","-","UC_NONE"},
    /*77*/{"-","Reserved","-","UC_NONE"},
    /*78*/{"-","Reserved","-","UC_NONE"},
    /*79*/{"-","Reserved","-","UC_NONE"},
    /*80*/{"-","Reserved","-","UC_NONE"},
    /*81*/{"-","Reserved","-","UC_NONE"},
    /*82*/{"-","Reserved","-","UC_NONE"},
    /*83*/{"-","Reserved","-","UC_NONE"},
    /*84*/{"-","Reserved","-","UC_NONE"},
    /*85*/{"-","Reserved","-","UC_NONE"},
    /*86*/{"-","Reserved","-","UC_NONE"},
    /*87*/{"-","Reserved","-","UC_NONE"},
    /*88*/{"-","Reserved","-","UC_NONE"},
    /*89*/{"-","Reserved","-","UC_NONE"},
    /*90*/{"-","Reserved","-","UC_NONE"},
    /*91*/{"-","Reserved","-","UC_NONE"},
    /*92*/{"-","Reserved","-","UC_NONE"},
    /*93*/{"-","Reserved","-","UC_NONE"},
    /*94*/{"-","Reserved","-","UC_NONE"},
    /*95*/{"-","Reserved","-","UC_NONE"},
    /*96*/{"-","Reserved","-","UC_NONE"},
    /*97*/{"-","Reserved","-","UC_NONE"},
    /*98*/{"-","Reserved","-","UC_NONE"},
    /*99*/{"-","Reserved","-","UC_NONE"},
    /*100*/{"-","Reserved","-","UC_NONE"},
    /*101*/{"-","Reserved","-","UC_NONE"},
    /*102*/{"-","Reserved","-","UC_NONE"},
    /*103*/{"-","Reserved","-","UC_NONE"},
    /*104*/{"-","Reserved","-","UC_NONE"},
    /*105*/{"-","Reserved","-","UC_NONE"},
    /*106*/{"-","Reserved","-","UC_NONE"},
    /*107*/{"-","Reserved","-","UC_NONE"},
    /*108*/{"-","Reserved","-","UC_NONE"},
    /*109*/{"-","Reserved","-","UC_NONE"},
    /*110*/{"-","Reserved","-","UC_NONE"},
    /*111*/{"-","Reserved","-","UC_NONE"},
    /*112*/{"-","Reserved","-","UC_NONE"},
    /*113*/{"-","Reserved","-","UC_NONE"},
    /*114*/{"-","Reserved","-","UC_NONE"},
    /*115*/{"-","Reserved","-","UC_NONE"},
    /*116*/{"-","Reserved","-","UC_NONE"},
    /*117*/{"-","Reserved","-","UC_NONE"},
    /*118*/{"-","Reserved","-","UC_NONE"},
    /*119*/{"-","Reserved","-","UC_NONE"},
    /*120*/{"-","Reserved","-","UC_NONE"},
    /*121*/{"-","Reserved","-","UC_NONE"},
    /*122*/{"-","Reserved","-","UC_NONE"},
    /*123*/{"-","Reserved","-","UC_NONE"},
    /*124*/{"-","Reserved","-","UC_NONE"},
    /*125*/{"-","Reserved","-","UC_NONE"},
    /*126*/{"-","Reserved","-","UC_NONE"},
    /*127*/{"-","Reserved","-","UC_NONE"},
    /*128*/{"-","Reserved","-","UC_NONE"},
    /*129*/{"-","Reserved","-","UC_NONE"},
    /*130*/{"-","Reserved","-","UC_NONE"},
    /*131*/{"-","Reserved","-","UC_NONE"},
    /*132*/{"-","Reserved","-","UC_NONE"},
    /*133*/{"-","Reserved","-","UC_NONE"},
    /*134*/{"-","Reserved","-","UC_NONE"},
    /*135*/{"-","Reserved","-","UC_NONE"},
    /*136*/{"-","Reserved","-","UC_NONE"},
    /*137*/{"-","Reserved","-","UC_NONE"},
    /*138*/{"-","Reserved","-","UC_NONE"},
    /*139*/{"-","Reserved","-","UC_NONE"},
    /*140*/{"-","Reserved","-","UC_NONE"},
    /*141*/{"-","Reserved","-","UC_NONE"},
    /*142*/{"-","Reserved","-","UC_NONE"},
    /*143*/{"-","Reserved","-","UC_NONE"},
    /*144*/{"-","Reserved","-","UC_NONE"},
    /*145*/{"-","Reserved","-","UC_NONE"},
    /*146*/{"-","Reserved","-","UC_NONE"},
    /*147*/{"-","Reserved","-","UC_NONE"},
    /*148*/{"-","Reserved","-","UC_NONE"},
    /*149*/{"-","Reserved","-","UC_NONE"},
    /*150*/{"-","Reserved","-","UC_NONE"},
    /*151*/{"-","Reserved","-","UC_NONE"},
    /*152*/{"-","Reserved","-","UC_NONE"},
    /*153*/{"-","Reserved","-","UC_NONE"},
    /*154*/{"-","Reserved","-","UC_NONE"},
    /*155*/{"-","Reserved","-","UC_NONE"},
    /*156*/{"-","Reserved","-","UC_NONE"},
    /*157*/{"-","Reserved","-","UC_NONE"},
    /*158*/{"-","Reserved","-","UC_NONE"},
    /*159*/{"-","Reserved","-","UC_NONE"},
    /*160*/{"-","Reserved","-","UC_NONE"},
    /*161*/{"-","Reserved","-","UC_NONE"},
    /*162*/{"-","Reserved","-","UC_NONE"},
    /*163*/{"-","Reserved","-","UC_NONE"},
    /*164*/{"-","Reserved","-","UC_NONE"},
    /*165*/{"-","Reserved","-","UC_NONE"},
    /*166*/{"-","Reserved","-","UC_NONE"},
    /*167*/{"-","Reserved","-","UC_NONE"},
    /*168*/{"-","Reserved","-","UC_NONE"},
    /*169*/{"-","Reserved","-","UC_NONE"},
    /*170*/{"-","Reserved","-","UC_NONE"},
    /*171*/{"-","Reserved","-","UC_NONE"},
    /*172*/{"-","Reserved","-","UC_NONE"},
    /*173*/{"-","Reserved","-","UC_NONE"},
    /*174*/{"-","Reserved","-","UC_NONE"},
    /*175*/{"-","Reserved","-","UC_NONE"},
    /*176*/{"-","Reserved","-","UC_NONE"},
    /*177*/{"-","Reserved","-","UC_NONE"},
    /*178*/{"-","Reserved","-","UC_NONE"},
    /*179*/{"-","Reserved","-","UC_NONE"},
    /*180*/{"-","Reserved","-","UC_NONE"},
    /*181*/{"-","Reserved","-","UC_NONE"},
    /*182*/{"-","Reserved","-","UC_NONE"},
    /*183*/{"-","Reserved","-","UC_NONE"},
    /*184*/{"-","Reserved","-","UC_NONE"},
    /*185*/{"-","Reserved","-","UC_NONE"},
    /*186*/{"-","Reserved","-","UC_NONE"},
    /*187*/{"-","Reserved","-","UC_NONE"},
    /*188*/{"-","Reserved","-","UC_NONE"},
    /*189*/{"-","Reserved","-","UC_NONE"},
    /*190*/{"-","Reserved","-","UC_NONE"},
    /*191*/{"-","Reserved","-","UC_NONE"},
    /*192*/{"LFTX","Surface Lifted Index","K","UC_NONE"},
    /*193*/{"4LFTX","Best (4 layer) Lifted Index","K","UC_NONE"},
    /*194*/{"RI","Richardson Number","Numeric","UC_NONE"},
    /*195*/{"CWDI","Convective Weather Detection Index","-","UC_NONE"},
    /*196*/{"UVI","Ultra Violet Index","W/m^2","UC_NONE"},
    /*197*/{"UPHL","Updraft Helicity","m^2/s^2","UC_NONE"},
    /*198*/{"LAI","Leaf Area Index","Numeric","UC_NONE"},
    /*199*/{"MXUPHL","Hourly Maximum of Updraft Helicity over Layer 2km to 5 km AGL","m^2/s^2","UC_NONE"},
    /*200*/{"MNUPHL","Hourly Minimum of Updraft Helicity","m^2/s^2","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_10_0[46] = {
    /*0*/{"WVSP1","Wave spectra (1)","-","UC_NONE"},
    /*1*/{"WVSP2","Wave spectra (2)","-","UC_NONE"},
    /*2*/{"WVSP3","Wave spectra (3)","-","UC_NONE"},
    /*3*/{"HTSGW","Significant height of combined wind waves and swell","m","UC_M2Feet"},
    /*4*/{"WVDIR","Direction of wind waves","Degree true","UC_NONE"},
    /*5*/{"WVHGT","Significant height of wind waves","m","UC_M2Feet"},
    /*6*/{"WVPER","Mean period of wind waves","s","UC_NONE"},
    /*7*/{"SWDIR","Direction of swell waves","Degree true","UC_NONE"},
    /*8*/{"SWELL","Significant height of swell waves","m","UC_NONE"},
    /*9*/{"SWPER","Mean period of swell waves","s","UC_NONE"},
    /*10*/{"DIRPW","Primary wave direction","Degree true","UC_NONE"},
    /*11*/{"PERPW","Primary wave mean period","s","UC_NONE"},
    /*12*/{"DIRSW","Secondary wave direction","Degree true","UC_NONE"},
    /*13*/{"PERSW","Secondary wave mean period","s","UC_NONE"},
    /*14*/{"WWSDIR","Direction of Combined Wind Waves and Swell","Degree true","UC_NONE"},
    /*15*/{"MWSPER","Mean Period of Combined Wind Waves and Swell","s","UC_NONE"},
    /*16*/{"CDWW","Coefficient of Drag With Waves","-","UC_NONE"},
    /*17*/{"FRICV","Friction Velocity","m/s","UC_NONE"},
    /*18*/{"WSTR","Wave Stress","N/(m^2)","UC_NONE"},
    /*19*/{"NWSTR","Normalised Waves Stress","-","UC_NONE"},
    /*20*/{"MSSW","Mean Square Slope of Waves","-","UC_NONE"},
    /*21*/{"USSD","U-component Surface Stokes Drift","m/s","UC_NONE"},
    /*22*/{"VSSD","V-component Surface Stokes Drift","m/s","UC_NONE"},
    /*23*/{"PMAXWH","Period of Maximum Individual Wave Height","s","UC_NONE"},
    /*24*/{"MAXWH","Maximum Individual Wave Height","m","UC_NONE"},
    /*25*/{"IMWF","Inverse Mean Wave Frequency","s","UC_NONE"},
    /*26*/{"IMFWW","Inverse Mean Frequency of The Wind Waves","s","UC_NONE"},
    /*27*/{"IMFTSW","Inverse Mean Frequency of The Total Swell","s","UC_NONE"},
    /*28*/{"MZWPER","Mean Zero-Crossing Wave Period","s","UC_NONE"},
    /*29*/{"MZPWW","Mean Zero-Crossing Period of The Wind Waves","s","UC_NONE"},
    /*30*/{"MZPTSW","Mean Zero-Crossing Period of The Total Swell","s","UC_NONE"},
    /*31*/{"WDIRW","Wave Directional Width","-","UC_NONE"},
    /*32*/{"DIRWWW","Directional Width of The Wind Waves","-","UC_NONE"},
    /*33*/{"DIRWTS","Directional Width of The Total Swell","-","UC_NONE"},
    /*34*/{"PWPER","Peak Wave Period","s","UC_NONE"},
    /*35*/{"PPERWW","Peak Period of The Wind Waves","s","UC_NONE"},
    /*36*/{"PPERTS","Peak Period of The Total Swell","s","UC_NONE"},
    /*37*/{"ALTWH","Altimeter Wave Height","m","UC_NONE"},
    /*38*/{"ALCWH","Altimeter Corrected Wave Height","m","UC_NONE"},
    /*39*/{"ALRRC","Altimeter Range Relative Correction","-","UC_NONE"},
    /*40*/{"MNWSOW","10 Metre Neutral Wind Speed Over Waves","m/s","UC_NONE"},
    /*41*/{"MWDIRW","10 Metre Wind Direction Over Waves","Degree true","UC_NONE"},
    /*42*/{"WESP","Wave Energy Spectrum","s/((m^2)*rad)","UC_NONE"},
    /*43*/{"KSSEW","Kurtosis of The Sea Surface Elevation Due to Waves","-","UC_NONE"},
    /*44*/{"BENINX","Benjamin-Feir Index","-","UC_NONE"},
    /*45*/{"SPFTR","Spectral Peakedness Factor","1/s","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_10_1[5] = {
    /*0*/{"DIRC","Current direction","Degree true","UC_NONE"},
    /*1*/{"SPC","Current speed","m/s","UC_NONE"},
    /*2*/{"UOGRD","u-component of current","m/s","UC_NONE"},
    /*3*/{"VOGRD","v-component of current","m/s","UC_NONE"},
    /*4*/{"RIPCOP","Rip Current Occurrence Probability","%","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_10_191[4] = {
    /*0*/{"TSEC","Seconds prior to initial reference time (defined in Section 1)","s","UC_NONE"},
    /*1*/{"MOSF","Meridonal Overturning Stream Function","m^3/s","UC_NONE"},
    /*2*/{"","Reserved","-","UC_NONE"},
    /*3*/{"DSLOBS","Days Since Last Observation","d","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_10_2[13] = {
    /*0*/{"ICEC","Ice cover","Proportion","UC_NONE"},
    /*1*/{"ICETK","Ice thinkness","m","UC_NONE"},
    /*2*/{"DICED","Direction of ice drift","Degree true","UC_NONE"},
    /*3*/{"SICED","Speed of ice drift","m/s","UC_NONE"},
    /*4*/{"UICE","u-component of ice drift","m/s","UC_NONE"},
    /*5*/{"VICE","v-component of ice drift","m/s","UC_NONE"},
    /*6*/{"ICEG","Ice growth rate","m/s","UC_NONE"},
    /*7*/{"ICED","Ice divergence","1/s","UC_NONE"},
    /*8*/{"ICET","Ice temperature","K","UC_NONE"},
    /*9*/{"ICEPRS","Module of Ice Internal Pressure","Pa*m","UC_NONE"},
    /*10*/{"ZVCICEP","Zonal Vector Component of Vertically Integrated Ice Internal Pressure","Pa*m","UC_NONE"},
    /*11*/{"MVCICEP","Meridional Vector Component of Vertically Integrated Ice Internal Pressure","Pa*m","UC_NONE"},
    /*12*/{"CICES","Compressive Ice Strength","N/m","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_10_3[3] = {
    /*0*/{"WTMP","Water temperature","K","UC_NONE"},
    /*1*/{"DSLM","Deviation of sea level from mean","m","UC_NONE"},
    /*2*/{"CH","Heat Exchange Coefficient","","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_10_4[16] = {
    /*0*/{"MTHD","Main thermocline depth","m","UC_NONE"},
    /*1*/{"MTHA","Main thermocline anomaly","m","UC_NONE"},
    /*2*/{"TTHDP","Transient thermocline depth","m","UC_NONE"},
    /*3*/{"SALTY","Salinity","kg/kg","UC_NONE"},
    /*4*/{"OVHD","Ocean Vertical Heat Diffusivity","m^2/s","UC_NONE"},
    /*5*/{"OVSD","Ocean Vertical Salt Diffusivity","m^2/s","UC_NONE"},
    /*6*/{"OVMD","Ocean Vertical Momentum Diffusivity","m^2/s","UC_NONE"},
    /*7*/{"BATHY","Bathymetry","m","UC_NONE"},
    /*8*/{"","Reserved","-","UC_NONE"},
    /*9*/{"","Reserved","-","UC_NONE"},
    /*10*/{"","Reserved","-","UC_NONE"},
    /*11*/{"SFSALP","Shape Factor With Respect To Salinity Profile","","UC_NONE"},
    /*12*/{"SFTMPP","Shape Factor With Respect To Temperature Profile In Thermocline","","UC_NONE"},
    /*13*/{"ACWSRD","Attenuation Coefficient Of Water With Respect to Solar Radiation","1/m","UC_NONE"},
    /*14*/{"WDEPTH","Water Depth","m","UC_NONE"},
    /*15*/{"WTMPSS","Water Temperature","K","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_1_0[7] = {
    /*0*/{"FFLDG","Flash flood guidance","kg/(m^2)","UC_NONE"},
    /*1*/{"FFLDRO","Flash flood runoff","kg/(m^2)","UC_NONE"},
    /*2*/{"RSSC","Remotely sensed snow cover","50=no-snow/no-cloud; 100=Clouds; 250=Snow; 255=missing","UC_NONE"},
    /*3*/{"ESCT","Elevation of snow covered terrain","0-90=elevation in increments of 100m; 254=clouds; 255=missing","UC_NONE"},
    /*4*/{"SWEPON","Snow water equivalent percent of normal","%","UC_NONE"},
    /*5*/{"BGRUN","Baseflow-groundwater runoff","kg/(m^2)","UC_NONE"},
    /*6*/{"SSRUN","Storm surface runoff","kg/(m^2)","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_1_1[3] = {
    /*0*/{"CPPOP","Conditional percent precipitation amount fractile for an overall period","kg/(m^2)","UC_NONE"},
    /*1*/{"PPOSP","Percent precipitation in a sub-period of an overall period","%","UC_NONE"},
    /*2*/{"PoP","Probability of 0.01 inch of precipitation","%","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_2_0[39] = {
    /*0*/{"LAND","Land cover (1=land; 2=sea)","Proportion","UC_NONE"},
    /*1*/{"SFCR","Surface roughness","m","UC_NONE"},
    /*2*/{"TSOIL","Soil temperature","K","UC_NONE"},
    /*3*/{"SOILM","Soil moisture content","kg/(m^2)","UC_NONE"},
    /*4*/{"VEG","Vegetation","%","UC_NONE"},
    /*5*/{"WATR","Water runoff","kg/(m^2)","UC_NONE"},
    /*6*/{"EVAPT","Evapotranspiration","1/(kg^2 s)","UC_NONE"},
    /*7*/{"MTERH","Model terrain height","m","UC_NONE"},
    /*8*/{"LANDU","Land use","1=Urban land; 2=agriculture; 3=Range Land; 4=Deciduous forest; 5=Coniferous forest; 6=Forest/wetland; 7=Water; 8=Wetlands; 9=Desert; 10=Tundra; 11=Ice; 12=Tropical forest; 13=Savannah","UC_NONE"},
    /*9*/{"SOILW","Volumetric soil moisture content","Proportion","UC_NONE"},
    /*10*/{"GFLUX","Ground heat flux","W/(m^2)","UC_NONE"},
    /*11*/{"MSTAV","Moisture availability","%","UC_NONE"},
    /*12*/{"SFEXC","Exchange coefficient","(kg/(m^3))(m/s)","UC_NONE"},
    /*13*/{"CNWAT","Plant canopy surface water","kg/(m^2)","UC_NONE"},
    /*14*/{"BMIXL","Blackadar's mixing length scale","m","UC_NONE"},
    /*15*/{"CCOND","Canopy conductance","m/s","UC_NONE"},
    /*16*/{"RSMIN","Minimal stomatal resistance","s/m","UC_NONE"},
    /*17*/{"WILT","Wilting point","Proportion","UC_NONE"},
    /*18*/{"RCS","Solar parameter in canopy conductance","Proportion","UC_NONE"},
    /*19*/{"RCT","Temperature parameter in canopy conductance","Proportion","UC_NONE"},
    /*20*/{"RCSOL","Soil moisture parameter in canopy conductance","Proportion","UC_NONE"},
    /*21*/{"RCQ","Humidity parameter in canopy conductance","Proportion","UC_NONE"},
    /*22*/{"SOILM","Soil moisture","kg/m^3","UC_NONE"},
    /*23*/{"CISOILW","Column-integrated soil water","kg/m^2","UC_NONE"},
    /*24*/{"HFLUX","Heat flux","W/m^2","UC_NONE"},
    /*25*/{"VSOILM","Volumetric soil moisture","m^3/m^3","UC_NONE"},
    /*26*/{"WILT","Wilting point","kg/m^3","UC_NONE"},
    /*27*/{"VWILTM","Volumetric wilting moisture","m^3/m^3","UC_NONE"},
    /*28*/{"LEAINX","Leaf Area Index","Numeric","UC_NONE"},
    /*29*/{"EVGFC","Evergreen Forest Cover","Proportion","UC_NONE"},
    /*30*/{"DECFC","Deciduous Forest Cover","Proportion","UC_NONE"},
    /*31*/{"NDVINX","Normalized Differential Vegetation Index (NDVI)","Numeric","UC_NONE"},
    /*32*/{"RDVEG","Root Depth of Vegetation","m","UC_NONE"},
    /*33*/{"WROD","Water Runoff and Drainage","kg/(m^2)","UC_NONE"},
    /*34*/{"SFCWRO","Surface Water Runoff","kg/(m^2)","UC_NONE"},
    /*35*/{"TCLASS","Tile Class","0=Reserved; 1=Evergreen broadleaved forest; 2=Deciduous broadleaved closed forest; 3=Deciduous broadleaved open forest; 4=Evergreen needle-leaf forest; 5=Deciduous needle-leaf forest; 6=Mixed leaf trees; 7=Fresh water flooded trees; 8=Saline water flooded trees; 9=Mosaic tree/natural vegetation; 10=Burnt tree cover; 11=Evergreen shurbs closed-open;  12=Deciduous shurbs closed-open; 13=Herbaceous vegetation closed-open; 14=Sparse herbaceous or grass; 15=Flooded shurbs or herbaceous; 16=Cultivated and managed areas; 17=Mosaic crop/tree/natural vegetation; 18=Mosaic crop/shrub/grass; 19=Bare areas; 20=Water; 21=Snow and ice; 22=Artificial surface; 23=Ocean; 24=Irrigated croplands; 25=Rain fed croplands; 26=Mosaic cropland (50-70%)-vegetation (20-50%); 27=Mosaic vegetation (50-70%)-cropland (20-50%); 28=Closed broadleaved evergreen forest; 29=Closed needle-leaved evergreen forest; 30=Open needle-leaved deciduous forest; 31=Mixed broadleaved and needle-leave forest; 32=Mosaic shrubland (50-70%)-grassland (20-50%); 33=Mosaic grassland (50-70%)-shrubland (20-50%); 34=Closed to open shrubland; 35=Sparse vegetation; 36=Closed to open forest regularly flooded; 37=Closed forest or shrubland permanently flooded; 38=Closed to open grassland regularly flooded; 39=Undefined; ","UC_NONE"},
    /*36*/{"TFRCT","Tile Fraction","Proportion","UC_NONE"},
    /*37*/{"TPERCT","Tile Percentage","%","UC_NONE"},
    /*38*/{"SOILVIC","Soil Volumetric Ice Content (Water Equivalent) ","m^3/m^3","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_2_3[28] = {
    /*0*/{"SOTYP","Soil type","1=Sand; 2=Loamy sand; 3=Sandy loam; 4=Silt loam; 5=Organic (redefined); 6=Sandy clay loam; 7=Silt clay loam; 8=Clay loam; 9=Sandy clay; 10=Silty clay; 11=Clay","UC_NONE"},
    /*1*/{"UPLST","Upper layer soil temperature","K","UC_NONE"},
    /*2*/{"UPLSM","Upper layer soil moisture","kg/(m^3)","UC_NONE"},
    /*3*/{"LOWLSM","Lower layer soil moisture","kg/(m^3)","UC_NONE"},
    /*4*/{"BOTLST","Bottom layer soil temperature","K","UC_NONE"},
    /*5*/{"SOILL","Liquid volumetric soil moisture (non-frozen)","Proportion","UC_NONE"},
    /*6*/{"RLYRS","Number of soil layers in root zone","Numeric","UC_NONE"},
    /*7*/{"SMREF","Transpiration stress-onset (soil moisture)","Proportion","UC_NONE"},
    /*8*/{"SMDRY","Direct evaporation cease (soil moisture)","Proportion","UC_NONE"},
    /*9*/{"POROS","Soil porosity","Proportion","UC_NONE"},
    /*10*/{"LIQVSM","Liquid volumetric soil moisture (non-frozen)","m^3/m^3","UC_NONE"},
    /*11*/{"VOLTSO","Volumetric transpiration stress-onset (soil moisture)","m^3/m^3","UC_NONE"},
    /*12*/{"TRANSO","Transpiration stress-onset (soil moisture)","kg/m^3","UC_NONE"},
    /*13*/{"VOLDEC","Volumetric direct evaporation cease (soil moisture)","m^3/m^3","UC_NONE"},
    /*14*/{"DIREC","Direct evaporation cease (soil moisture)","kg/m^3","UC_NONE"},
    /*15*/{"SOILP","Soil porosity","m^3/m^3","UC_NONE"},
    /*16*/{"VSOSM","Volumetric saturation of soil moisture","m^3/m^3","UC_NONE"},
    /*17*/{"SATOSM","Saturation of soil moisture","kg/m^3","UC_NONE"},
    /*18*/{"SOILTMP","Soil Temperature","K","UC_NONE"},
    /*19*/{"SOILMOI","Soil Moisture","kg/(m^3)","UC_NONE"},
    /*20*/{"CISOILM","Column-Integrated Soil Moisture","kg/(m^2)","UC_NONE"},
    /*21*/{"SOILICE","Soil Ice","kg/(m^3)","UC_NONE"},
    /*22*/{"CISICE","Column-Integrated Soil Ice","kg/(m^2)","UC_NONE"},
    /*23*/{"LWSNWP","Liquid Water in Snow Pack","kg/(m^2)","UC_NONE"},
    /*24*/{"FRSTINX","Frost Index","kg/day","UC_NONE"},
    /*25*/{"SNWDEB","Snow Depth at Elevation Bands","kg/(m^2)","UC_NONE"},
    /*26*/{"SHFLX","Soil Heat Flux","W/(m^2)","UC_NONE"},
    /*27*/{"SOILDEP","Soil Depth","m","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_3_0[10] = {
    /*0*/{"SRAD","Scaled radiance","Numeric","UC_NONE"},
    /*1*/{"SALBEDO","Scaled albedo","Numeric","UC_NONE"},
    /*2*/{"SBTMP","Scaled brightness temperature","Numeric","UC_NONE"},
    /*3*/{"SPWAT","Scaled precipitable water","Numeric","UC_NONE"},
    /*4*/{"SLFTI","Scaled lifted index","Numeric","UC_NONE"},
    /*5*/{"SCTPRES","Scaled cloud top pressure","Numeric","UC_NONE"},
    /*6*/{"SSTMP","Scaled skin temperature","Numeric","UC_NONE"},
    /*7*/{"CLOUDM","Cloud mask","0=clear over water; 1=clear over land; 2=cloud","UC_NONE"},
    /*8*/{"PIXST","Pixel scene type","0=No scene; 1=needle; 2=broad-leafed; 3=Deciduous needle; 4=Deciduous broad-leafed; 5=Deciduous mixed; 6=Closed shrub; 7=Open shrub; 8=Woody savannah; 9=Savannah; 10=Grassland; 11=wetland; 12=Cropland; 13=Urban; 14=crops; 15=snow; 16=Desert; 17=Water; 18=Tundra; 97=Snow on land; 98=Snow on water; 99=Sun-glint; 100=General cloud; 101=fog Stratus; 102=Stratocumulus; 103=Low cloud; 104=Nimbotratus; 105=Altostratus; 106=Medium cloud; 107=Cumulus; 108=Cirrus; 109=High cloud; 110=Unknown cloud","UC_NONE"},
    /*9*/{"FIREDI","Fire detection indicator","0=No fire detected; 1=Possible fire detected; 2=Probable fire detected","UC_NONE"}
};
const GRIB2SurfTable grib2_table_4_2_3_1[30] = {
    /*0*/{"ESTP","Estimated precipitation","kg/(m^2)","UC_NONE"},
    /*1*/{"IRRATE","Instantaneous rain rate","kg/(m^2*s)","UC_NONE"},
    /*2*/{"CTOPH","Cloud top height","kg/(m^2*s)","UC_NONE"},
    /*3*/{"CTOPHQI","Cloud top height quality indicator","0=Nominal cloud top height quality; 1=Fog in segment; 2=Poor quality height estimation; 3=Fog in segment and poor quality height estimation","UC_NONE"},
    /*4*/{"ESTUGRD","Estimated u component of wind","m/s","UC_NONE"},
    /*5*/{"ESTVGRD","Estimated v component of wind","m/s","UC_NONE"},
    /*6*/{"NPIXU","Number of pixels used","Numeric","UC_NONE"},
    /*7*/{"SOLZA","Solar zenith angle","Degree","UC_NONE"},
    /*8*/{"RAZA","Relative azimuth angle","Degree","UC_NONE"},
    /*9*/{"RFL06","Reflectance in 0.6 micron channel","%","UC_NONE"},
    /*10*/{"RFL08","Reflectance in 0.8 micron channel","%","UC_NONE"},
    /*11*/{"RFL16","Reflectance in 1.6 micron channel","%","UC_NONE"},
    /*12*/{"RFL39","Reflectance in 3.9 micron channel","%","UC_NONE"},
    /*13*/{"ATMDIV","Atmospheric divergence","1/s","UC_NONE"},
    /*14*/{"CBTMP","Cloudy Brightness Temperature","K","UC_NONE"},
    /*15*/{"CSBTMP","Clear Sky Brightness Temperature","K","UC_NONE"},
    /*16*/{"CLDRAD","Cloudy Radiance (with respect to wave number)","W/(m*sr)","UC_NONE"},
    /*17*/{"CSKYRAD","Clear Sky Radiance (with respect to wave number)","W/(m*sr)","UC_NONE"},
    /*18*/{"","Reserved","-","UC_NONE"},
    /*19*/{"WINDS","Wind Speed","m/s","UC_NONE"},
    /*20*/{"AOT06","Aerosol Optical Thickness at 0.635 µm","","UC_NONE"},
    /*21*/{"AOT08","Aerosol Optical Thickness at 0.810 µm","","UC_NONE"},
    /*22*/{"AOT16","Aerosol Optical Thickness at 1.640 µm","","UC_NONE"},
    /*23*/{"ANGCOE","Angstrom Coefficient","","UC_NONE"},
    /*24*/{"","Reserved","-","UC_NONE"},
    /*25*/{"","Reserved","-","UC_NONE"},
    /*26*/{"","Reserved","-","UC_NONE"},
    /*27*/{"BRFLF","Bidirectional Reflecance Factor","Numeric","UC_NONE"},
    /*28*/{"SPBRT","Brightness Temperature","K","UC_NONE"},
    /*29*/{"SRAD","Scaled Radiance","Numeric","UC_NONE"}
};

static const char* GetGRIB2_CSVFilename(const char* pszFilename)
{
    return pszFilename;
    //const char* pszGribTableDirectory = CPLGetConfigOption("GRIB_RESOURCE_DIR", nullptr);
    //if( pszGribTableDirectory )
    //{
    //    const char* pszFullFilename = CPLFormFilename(pszGribTableDirectory, pszFilename, nullptr);
    //    VSIStatBufL sStat;
    //    if( VSIStatL(pszFullFilename, &sStat) == 0 )
    //        return pszFullFilename;
    //    return nullptr;
    //}
    //const char* pszRet = CSVFilename(pszFilename);
    //// CSVFilename() returns the same content as pszFilename if it does not
    //// find the file.
    //if( pszRet && strcmp(pszRet, pszFilename) == 0 )
    //    return nullptr;
    //return pszRet;
}

//const char *centerLookup (unsigned short int center)
//{
//    const char* pszFilename = GetGRIB2_CSVFilename("grib2_center.csv");
//    if( pszFilename == nullptr )
//    {
//        CPLError(CE_Failure, CPLE_AppDefined, "Cannot find grib2_center.csv");
//        return nullptr;
//    }
//    const char* pszName = CSVGetField( pszFilename, "code", CPLSPrintf("%d", center),
//                                       CC_Integer, "name" );
//    if( pszName && pszName[0] == 0 )
//        pszName = nullptr;
//    return pszName;
//}
//
//const char *subCenterLookup(unsigned short int center,
//                            unsigned short int subcenter)
//{
//    const char* pszFilename = GetGRIB2_CSVFilename("grib2_subcenter.csv");
//    if( pszFilename == nullptr )
//    {
//        CPLError(CE_Failure, CPLE_AppDefined, "Cannot find grib2_subcenter.csv");
//        return nullptr;
//    }
//    int iCenter = CSVGetFileFieldId(pszFilename,"center_code");
//    int iSubCenter = CSVGetFileFieldId(pszFilename,"subcenter_code");
//    int iName = CSVGetFileFieldId(pszFilename,"name");
//    if( iCenter < 0 || iSubCenter < 0 || iName < 0 )
//    {
//        CPLError(CE_Failure, CPLE_AppDefined, "Bad structure for %s", pszFilename);
//        return nullptr;
//    }
//    CSVRewind(pszFilename);
//    while( char** papszFields = CSVGetNextLine(pszFilename) )
//    {
//        if( atoi(papszFields[iCenter]) == static_cast<int>(center) &&
//            atoi(papszFields[iSubCenter]) == static_cast<int>(subcenter) )
//        {
//            return papszFields[iName];
//        }
//    }
//    return nullptr;
//}
//
//#ifdef unused_by_GDAL
//const char *processLookup (unsigned short int center, unsigned char process)
//{
//    const char* pszFilename = GetGRIB2_CSVFilename("grib2_process.csv");
//    if( pszFilename == nullptr )
//    {
//        CPLError(CE_Failure, CPLE_AppDefined, "Cannot find grib2_process.csv");
//        return nullptr;
//    }
//    int iCenter = CSVGetFileFieldId(pszFilename,"center_code");
//    int iProcess = CSVGetFileFieldId(pszFilename,"process_code");
//    int iName = CSVGetFileFieldId(pszFilename,"name");
//    if( iCenter < 0 || iProcess < 0 || iName < 0 )
//    {
//        CPLError(CE_Failure, CPLE_AppDefined, "Bad structure for %s", pszFilename);
//        return nullptr;
//    }
//    CSVRewind(pszFilename);
//    while( char** papszFields = CSVGetNextLine(pszFilename) )
//    {
//        if( atoi(papszFields[iCenter]) == static_cast<int>(center) &&
//            atoi(papszFields[iProcess]) == static_cast<int>(process) )
//        {
//            return papszFields[iName];
//        }
//    }
//    return nullptr;
//}
//#endif
//
typedef struct {
    const char *GRIB2name, *NDFDname;
} NDFD_AbrevOverrideTable;
//
//
static unit_convert GetUnitConvertFromString(const char* pszUnitConv)
{
    unit_convert convert;
    if( strcmp(pszUnitConv, "UC_NONE") == 0 )
        convert = UC_NONE;
    else if( strcmp(pszUnitConv, "UC_K2F") == 0 )
        convert = UC_K2F;
    else if( strcmp(pszUnitConv, "UC_InchWater") == 0 )
        convert = UC_InchWater;
    else if( strcmp(pszUnitConv, "UC_M2Feet") == 0 )
        convert = UC_M2Feet;
    else if( strcmp(pszUnitConv, "UC_M2Inch") == 0 )
        convert = UC_M2Inch;
    else if( strcmp(pszUnitConv, "UC_MS2Knots") == 0 )
        convert = UC_MS2Knots;
    else if( strcmp(pszUnitConv, "UC_LOG10") == 0 )
        convert = UC_LOG10;
    else if( strcmp(pszUnitConv, "UC_UVIndex") == 0 )
        convert = UC_UVIndex;
    else if( strcmp(pszUnitConv, "UC_M2StatuteMile") == 0 )
        convert = UC_M2StatuteMile;
    else
    {
        convert = UC_NONE;
        //CPLError(CE_Warning, CPLE_AppDefined,
        //         "Unhandled unit conversion: %s", pszUnitConv);
    }
    return convert;
}
//
///*****************************************************************************
// * GetGrib2Table4_2_Record() --
// *
// * PURPOSE
// *   Chooses the correct Parameter table depending on what is in the GRIB2
// * message's "Product Definition Section".
// *
// * ARGUMENTS
// * prodType = The product type (meteo, hydro, land, space, ocean, etc) (In)
// *      cat = The category inside the product (Input)
// *   subcat = The GRIB2 section 4 "Specific subcategory of Product". (Input)
// * shortName= Pointer to short name of the parameter, or nullptr(Output)
// *     name = Pointer to longer name of the parameter, or nullptr (Output)
// *     unit = Pointer to unit name, or nullptr (Output)
// *  convert = Pointer to unit converter, or nullptr (Output)
// *
// * FILES/DATABASES: None
// *
// * RETURNS: TRUE in case of success
// *****************************************************************************
// */
static int GetGrib2Table4_2_Record(int prodType, int cat, int subcat,
    String& shortName,
    String& name,
    String& unit,
    unit_convert* convert)
{
    char buffer[128];
    CPLSPrintf(buffer, "grib2_table_4_2_%d_%d",
        prodType, cat);

    String name2(buffer);
    const GRIB2SurfTable* table = nullptr;

    if(name2 == "grib2_table_4_2_0_0") {
        table = grib2_table_4_2_0_0;
        if (subcat >= sizeof(grib2_table_4_2_0_0) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_1") {
        table = grib2_table_4_2_0_1;
        if (subcat >= sizeof(grib2_table_4_2_0_1) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_13") {
        table = grib2_table_4_2_0_13;
        if (subcat >= sizeof(grib2_table_4_2_0_13) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_14") {
        table = grib2_table_4_2_0_14;
        if (subcat >= sizeof(grib2_table_4_2_0_14) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_15") {
        table = grib2_table_4_2_0_15;
        if (subcat >= sizeof(grib2_table_4_2_0_15) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_16") {
        table = grib2_table_4_2_0_16;
        if (subcat >= sizeof(grib2_table_4_2_0_16) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_17") {
        table = grib2_table_4_2_0_17;
        if (subcat >= sizeof(grib2_table_4_2_0_17) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_18") {
        table = grib2_table_4_2_0_18;
        if (subcat >= sizeof(grib2_table_4_2_0_18) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_19") {
        table = grib2_table_4_2_0_19;
        if (subcat >= sizeof(grib2_table_4_2_0_19) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_190") {
        table = grib2_table_4_2_0_190;
        if (subcat >= sizeof(grib2_table_4_2_0_190) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_191") {
        table = grib2_table_4_2_0_191;
        if (subcat >= sizeof(grib2_table_4_2_0_191) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_2") {
        table = grib2_table_4_2_0_2;
        if (subcat >= sizeof(grib2_table_4_2_0_2) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_20") {
        table = grib2_table_4_2_0_20;
        if (subcat >= sizeof(grib2_table_4_2_0_20) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_253") {
        table = grib2_table_4_2_0_253;
        if (subcat >= sizeof(grib2_table_4_2_0_253) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_3") {
        table = grib2_table_4_2_0_3;
        if (subcat >= sizeof(grib2_table_4_2_0_3) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_4") {
        table = grib2_table_4_2_0_4;
        if (subcat >= sizeof(grib2_table_4_2_0_4) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_5") {
        table = grib2_table_4_2_0_5;
        if (subcat >= sizeof(grib2_table_4_2_0_5) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_6") {
        table = grib2_table_4_2_0_6;
        if (subcat >= sizeof(grib2_table_4_2_0_6) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_0_7") {
        table = grib2_table_4_2_0_7;
        if (subcat >= sizeof(grib2_table_4_2_0_7) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_10_0") {
        table = grib2_table_4_2_10_0;
        if (subcat >= sizeof(grib2_table_4_2_10_0) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_10_1") {
        table = grib2_table_4_2_10_1;
        if (subcat >= sizeof(grib2_table_4_2_10_1) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_10_191") {
        table = grib2_table_4_2_10_191;
        if (subcat >= sizeof(grib2_table_4_2_10_191) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_10_2") {
        table = grib2_table_4_2_10_2;
        if (subcat >= sizeof(grib2_table_4_2_10_2) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_10_3") {
        table = grib2_table_4_2_10_3;
        if (subcat >= sizeof(grib2_table_4_2_10_3) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_10_4") {
        table = grib2_table_4_2_10_4;
        if (subcat >= sizeof(grib2_table_4_2_10_4) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_1_0") {
        table = grib2_table_4_2_1_0;
        if (subcat >= sizeof(grib2_table_4_2_1_0) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_1_1") {
        table = grib2_table_4_2_1_1;
        if (subcat >= sizeof(grib2_table_4_2_1_1) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_2_0") {
        table = grib2_table_4_2_2_0;
        if (subcat >= sizeof(grib2_table_4_2_2_0) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_2_3") {
        table = grib2_table_4_2_2_3;
        if (subcat >= sizeof(grib2_table_4_2_2_3) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_3_0") {
        table = grib2_table_4_2_3_0;
        if (subcat >= sizeof(grib2_table_4_2_3_0) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }
    else if(name2 == "grib2_table_4_2_3_1") {
        table = grib2_table_4_2_3_1;
        if (subcat >= sizeof(grib2_table_4_2_3_1) / sizeof(GRIB2SurfTable))
        {
            return FALSE;
        }
    }

    if(table == nullptr )
    {
        return FALSE;
    }

    shortName = table[subcat].shortname;
    name = table[subcat].name;
    unit = table[subcat].unit;
    *convert = GetUnitConvertFromString(table[subcat].unit);

    return TRUE;
}

//static int GetGrib2Table4_2_Record(int prodType, int cat, int subcat,
//    String& shortName,
//    String& name,
//    String& unit,
//    unit_convert* convert)
//{
//    char buffer[128];
//    CPLSPrintf(buffer, "grib2_table_4_2_%d_%d.csv",
//        prodType, cat);
//
//    const char* pszBaseFilename = buffer;
//
//    const char* pszFilename = GetGRIB2_CSVFilename(pszBaseFilename);
//    if (pszFilename == nullptr)
//    {
//        return -1;
//    }
//
//    String fileName = Singleton(Environment).getAppDir() + pszFilename;
//    std::ifstream ifs(fileName.c_str());
//    if (!ifs)
//    {
//        return FALSE;
//    }
//    OC::String line;
//    getline(ifs, line);
//    OC::StringVector sv = OC::StringUtil::split(line, ",");
//
//    int iSubcat = -1;
//    int iShortName = -1;
//    int iName = -1;
//    int iUnit = -1;
//    int iUnitConv = -1;
//    for (size_t i = 0; i < sv.size(); i++)
//    {
//        OC::String item = sv[i];
//        if (item == "subcat")
//        {
//            iSubcat = i;
//        }
//        else if (item == "short_name")
//        {
//            iShortName = i;
//        }
//        else if (item == "name")
//        {
//            iName = i;
//        }
//        else if (item == "unit")
//        {
//            iUnit = i;
//        }
//        else if (item == "unit_conv")
//        {
//            iUnitConv = i;
//        }
//    }
//
//    //int iSubcat = CSVGetFileFieldId(pszFilename,"subcat");
//    //int iShortName = CSVGetFileFieldId(pszFilename,"short_name");
//    //int iName = CSVGetFileFieldId(pszFilename,"name");
//    //int iUnit = CSVGetFileFieldId(pszFilename,"unit");
//    //int iUnitConv = CSVGetFileFieldId(pszFilename,"unit_conv");
//    if (iSubcat < 0 || iShortName < 0 || iName < 0 || iUnit < 0 || iUnitConv < 0)
//    {
//        //CPLError(CE_Failure, CPLE_AppDefined, "Bad structure for %s", pszFilename);
//        return -1;
//    }
//
//    while (getline(ifs, line))
//    {
//        OC::StringVector sv = OC::StringUtil::split(line, ",");
//        if (atoi(sv[iSubcat].c_str()) == subcat)
//        {
//            //if( shortName )
//            {
//                // Short name is unavailable from WMO-only entries, so
//                // use longer name
//                if (sv[iShortName][0] == 0)
//                    shortName = sv[iShortName];
//                else
//                    shortName = sv[iShortName];
//            }
//            //if( name )
//            name = sv[iName].c_str();
//            //if( unit )
//            unit = sv[iUnit].c_str();
//            if (convert)
//                *convert = GetUnitConvertFromString(sv[iUnitConv].c_str());
//            return TRUE;
//        }
//    }
//
//    //CSVRewind(pszFilename);
//    //while( char** papszFields = CSVGetNextLine(pszFilename) )
//    //{
//    //    if( atoi(papszFields[iSubcat]) == subcat )
//    //    {
//    //        if( shortName )
//    //        {
//    //            // Short name is unavailable from WMO-only entries, so
//    //            // use longer name
//    //            if( papszFields[iShortName][0] == 0 )
//    //                *shortName = papszFields[iName];
//    //            else
//    //                *shortName = papszFields[iShortName];
//    //        }
//    //        if( name )
//    //            *name = papszFields[iName];
//    //        if( unit )
//    //            *unit = papszFields[iUnit];
//    //        if( convert )
//    //            *convert = GetUnitConvertFromString(papszFields[iUnitConv]);
//    //        return TRUE;
//    //    }
//    //}
//    return FALSE;
//}

//
///* *INDENT-OFF* */
static const NDFD_AbrevOverrideTable NDFD_Override[] = {
   /*  0 */ {"TMP", "T"},
   /*  1 */ {"TMAX", "MaxT"},
   /*  2 */ {"TMIN", "MinT"},
   /*  3 */ {"DPT", "Td"},
   /*  4 */ {"APCP", "QPF"},
   /* Don't need SNOD for now. */
   /*  5 */ /* {"SNOD", "SnowDepth"}, */
   /*  6 */ {"WDIR", "WindDir"},
   /*  7 */ {"WIND", "WindSpd"},
   /*  8 */ {"TCDC", "Sky"},
   /*  9 */ {"WVHGT", "WaveHeight"},
   /* 10 */ {"ASNOW", "SnowAmt"},
   /* 11 */ {"GUST", "WindGust"},
   /* 12 */ {"MAXRH", "MaxRH"},                /* MPA added 201202 */
   /* 13 */ {"HTSGW", "WaveHeight"},           /* MPA added 201709 */
};
///* *INDENT-ON* */
//
int IsData_NDFD (unsigned short int center, unsigned short int subcenter)
{
   return ((center == 8) &&
           ((subcenter == GRIB2MISSING_u2) || (subcenter == 0)));
}

int IsData_MOS (unsigned short int center, unsigned short int subcenter)
{
   return ((center == 7) && (subcenter == 14));
}

//static const char* GetGrib2LocalTable4_2FileName(int center,
//                                                 int subcenter)
//{
//    const char* pszFilename = GetGRIB2_CSVFilename("grib2_table_4_2_local_index.csv");
//    if( pszFilename == nullptr )
//    {
//        return nullptr;
//    }
//    int iCenter = CSVGetFileFieldId(pszFilename,"center_code");
//    int iSubCenter = CSVGetFileFieldId(pszFilename,"subcenter_code");
//    int iFilename = CSVGetFileFieldId(pszFilename,"filename");
//    if( iCenter < 0 || iSubCenter < 0 || iFilename < 0 )
//    {
//        CPLError(CE_Failure, CPLE_AppDefined, "Bad structure for %s", pszFilename);
//        return nullptr;
//    }
//    CSVRewind(pszFilename);
//    while( char** papszFields = CSVGetNextLine(pszFilename) )
//    {
//        if( atoi(papszFields[iCenter]) == center )
//        {
//            if( papszFields[iSubCenter][0] == '\0' ||
//                atoi(papszFields[iSubCenter]) == subcenter )
//            {
//                return GetGRIB2_CSVFilename(papszFields[iFilename]);
//            }
//        }
//    }
//    return nullptr;
//}
//
///*****************************************************************************
// * GetGrib2LocalTable4_2_Record() --
// *
// * PURPOSE
// *   Return the parameter definition depending on what is in the GRIB2
// * message's "Product Definition Section" from a local parameter table
// * for a given center/subcenter.
// * Typically this is called after the default Choose_ParmTable was tried,
// * since it consists of all the local specs, and one has to linearly walk
// * through the table.
// *
// * ARGUMENTS
// *    center = The center that created the data. (Input)
// * subcenter = The subcenter that created the data. (Input)
// * prodType = The product type (meteo, hydro, land, space, ocean, etc) (In)
// *      cat = The category inside the product (Input)
// *   subcat = The GRIB2 section 4 "Specific subcategory of Product". (Input)
// * shortName= Pointer to short name of the parameter, or nullptr(Output)
// *     name = Pointer to longer name of the parameter, or nullptr (Output)
// *     unit = Pointer to unit name, or nullptr (Output)
// *  convert = Pointer to unit converter, or nullptr (Output)
// *
// * FILES/DATABASES: None
// *
// * RETURNS: TRUE in case of success
// *****************************************************************************
// */
//
static int GetGrib2LocalTable4_2_Record (int center,
                                         int subcenter,
                                         int prodType, int cat, int subcat,
                                         String& shortName,
                                         String& name,
                                         String& unit,
                                         unit_convert* convert)
{
   /* const char* pszFilename = GetGrib2LocalTable4_2FileName(center, subcenter);
    if( pszFilename == nullptr )
    {
        return -1;
    }
    int iProd = CSVGetFileFieldId(pszFilename,"prod");
    int iCat = CSVGetFileFieldId(pszFilename,"cat");
    int iSubcat = CSVGetFileFieldId(pszFilename,"subcat");
    int iShortName = CSVGetFileFieldId(pszFilename,"short_name");
    int iName = CSVGetFileFieldId(pszFilename,"name");
    int iUnit = CSVGetFileFieldId(pszFilename,"unit");
    int iUnitConv = CSVGetFileFieldId(pszFilename,"unit_conv");
    if( iProd < 0 || iCat < 0 || iSubcat < 0 || iShortName < 0 ||
        iName < 0 || iUnit < 0 || iUnitConv < 0 )
    {
        return -1;
    }
    CSVRewind(pszFilename);
    while( char** papszFields = CSVGetNextLine(pszFilename) )
    {
        if( atoi(papszFields[iProd]) == prodType &&
            atoi(papszFields[iCat]) == cat &&
            atoi(papszFields[iSubcat]) == subcat )
        {
            if( shortName )
                *shortName = papszFields[iShortName];
            if( name )
                *name = papszFields[iName];
            if( unit )
                *unit = papszFields[iUnit];
            if( convert )
                *convert = GetUnitConvertFromString(papszFields[iUnitConv]);
            return TRUE;
        }
    }*/
    return FALSE;
}

//
///*****************************************************************************
// * ParseElemName() --
// *
// * Arthur Taylor / MDL
// *
// * PURPOSE
// *   Converts a prodType, template, category and subcategory quadruple to the
// * ASCII string abbreviation of that variable.
// *   For example: 0, 0, 0, 0, = "T" for temperature.
// *
// * ARGUMENTS
// *    center = The center that created the data. (Input)
// * subcenter = The subcenter that created the data. (Input)
// *  prodType = The GRIB2, section 0 product type. (Input)
// *   templat = The GRIB2 section 4 template number. (Input)
// *       cat = The GRIB2 section 4 "General category of Product." (Input)
// *    subcat = The GRIB2 section 4 "Specific subcategory of Product". (Input)
// *   lenTime = The length of time over which statistics are done
// *             (see template 4.8). (Input)
// *     genID = The Generating process ID (used for GFS MOS) (Input)
// *  probType = For Probability templates (Input)
// * lowerProb = Lower Limit for probability templates. (Input)
// * upperProb = Upper Limit for probability templates. (Input)
// *      name = Short name for the data set (T, MaxT, etc) (Output)
// *   comment = Long form of the name (Temperature, etc) (Output)
// *      unit = What unit this variable is originally in (Output)
// *
// * FILES/DATABASES: None
// *
// * RETURNS: void
// *
// * HISTORY
// *   1/2004 Arthur Taylor (MDL/RSIS): Re-Created.
// *   6/2004 AAT: Added deltTime (because of Ozone issues).
// *   8/2004 AAT: Adjusted so template 9 gets units of % and no convert.
// *   3/2005 AAT: ReWrote to handle template 5, 9 and MOS.
// *   9/2005 AAT: Added code to handle MOS PoP06 vs MOS PoP12.
// *
// * NOTES
// *****************************************************************************
// */
///* Deal with probability templates 2/16/2006 */
static void ElemNameProb (uChar mstrVersion, uShort2 center, uShort2 subcenter, int prodType,
                          int templat,
                          uChar cat, uChar subcat, sInt4 lenTime,
                          uChar timeRangeUnit,
                          uChar timeIncrType,
                          uChar genID,
                          uChar probType,
                          double lowerProb, double upperProb, char **name,
                          char **comment, char **unit, int *convert)
{
   char f_isNdfd = IsData_NDFD (center, subcenter);
   char f_isMos = IsData_MOS (center, subcenter);

   *unit = (char *) malloc (strlen ("[%]") + 1);
   strcpy (*unit, "[%]");

   {
      // 25.4 mm = 1 inch
      const double tmp = upperProb * 25.4;

      // TODO(schwehr): Make a function and reuse it for other limit checks.
      if (upperProb > tmp ||
          tmp > (std::numeric_limits<int>::max)() ||
          tmp < (std::numeric_limits<int>::min)() ||
          CPLIsNan(tmp) ) {
         // TODO(schwehr): What is the correct response?
         errSprintf ("ERROR: upperProb out of range.  Setting to 0.\n");
         upperProb = 0.0;
      }
   }

   if (f_isNdfd || f_isMos) {
      /* Deal with NDFD/MOS handling of Prob Precip_Tot -> PoP12 */
      if ((prodType == 0) && (cat == 1) && (subcat == 8)) {
         if (probType == 0) {
            if (lenTime > 0) {
               if (timeRangeUnit == 3) {
                  mallocSprintf (name, "ProbPrcpBlw%02dm", lenTime);
                  mallocSprintf (comment, "%02d mon Prob of Precip below average", lenTime);
               } else if (timeRangeUnit == 4) {
                  mallocSprintf (name, "ProbPrcpBlw%02dy", lenTime);
                  mallocSprintf (comment, "%02d yr Prob of Precip below average", lenTime);
               } else {
                  mallocSprintf (name, "ProbPrcpBlw%02d", lenTime);
                  mallocSprintf (comment, "%02d hr Prob of Precip below average", lenTime);
               }
            } else {
               mallocSprintf (name, "ProbPrcpBlw");
               mallocSprintf (comment, "Prob of precip below average");
            }
         } else if (probType == 3) {
            if (lenTime > 0) {
               if (timeRangeUnit == 3) {
                  mallocSprintf (name, "ProbPrcpAbv%02dm", lenTime);
                  mallocSprintf (comment, "%02d mon Prob of Precip above average", lenTime);
               } else if (timeRangeUnit == 4) {
                  mallocSprintf (name, "ProbPrcpAbv%02dy", lenTime);
                  mallocSprintf (comment, "%02d yr Prob of Precip above average", lenTime);
               } else {
                  mallocSprintf (name, "ProbPrcpAbv%02d", lenTime);
                  mallocSprintf (comment, "%02d hr Prob of Precip above average", lenTime);
               }
            } else {
               mallocSprintf (name, "ProbPrcpAbv");
               mallocSprintf (comment, "Prob of precip above average");
            }
         } else {
            myAssert (probType == 1);
            if (lenTime > 0) {
               if (timeRangeUnit == 3) {
                  if (upperProb != (double) .254) {
                     mallocSprintf (name, "PoP%02dm-%03d", lenTime, (int) (upperProb / .254 + .5));
                  } else {
                     mallocSprintf (name, "PoP%02dm", lenTime);
                  }
                  mallocSprintf (comment, "%02d mon Prob of Precip > %g In.", lenTime, upperProb / 25.4);
               } else if (timeRangeUnit == 4) {
                  if (upperProb != (double) .254) {
                     mallocSprintf (name, "PoP%02dy-%03d", lenTime, (int) (upperProb / .254 + .5));
                  } else {
                     mallocSprintf (name, "PoP%02dy", lenTime);
                  }
                  mallocSprintf (comment, "%02d yr Prob of Precip > %g In.", lenTime, upperProb / 25.4);
               } else {
                  /* The 300 is to deal with an old NDFD encoding bug from 2002:
                   * PDS-S4 | Upper limit (scale value, scale factor) | 300 (3, -2)
                   * 25.4 mm = 1 inch.  Rain typically .01 inches = .254 mm
                   */
                  if ((upperProb != (double) .254) && (upperProb != (double) 300)) {
                     mallocSprintf (name, "PoP%02d-%03d", lenTime, (int) (upperProb / .254 + .5));
                  } else {
                     mallocSprintf (name, "PoP%02d", lenTime);
                  }
                  if (upperProb != (double) 300) {
                     mallocSprintf (comment, "%02d hr Prob of Precip > %g In.", lenTime, upperProb / 25.4);
                  } else {
                     mallocSprintf (comment, "%02d hr Prob of Precip > 0.01 In.", lenTime);
                  }
               }
            } else {
               if (upperProb != (double) .254) {
                  mallocSprintf (name, "PoP-p%03d", (int) (upperProb / .254 + .5));
               } else {
                  mallocSprintf (name, "PoP");
               }
               mallocSprintf (comment, "Prob of Precip > %g In.", upperProb / 25.4);
            }
         }
         *convert = UC_NONE;
         return;
      }
      /*
       * Deal with NDFD handling of Prob. Wind speeds.
       * There are different solutions for naming the Prob. Wind fields
       * AAT(Mine): ProbSurge5c
       */
      if ((prodType == 10) && (cat == 3) && (subcat == 192)) {
         myAssert (probType == 1);
         myAssert (lenTime > 0);
         if (timeIncrType == 2) {
            /* Incremental */
            mallocSprintf (name, "ProbSurge%02di",
                           (int) ((upperProb / 0.3048) + .5));
         } else {
            /* Cumulative */
            myAssert (timeIncrType == 192);
            mallocSprintf (name, "ProbSurge%02dc",
                           (int) ((upperProb / 0.3048) + .5));
         }
         if (timeRangeUnit == 3) {
            mallocSprintf (comment, "%02d mon Prob of Hurricane Storm Surge > %g "
                           "m", lenTime, upperProb);
         } else if (timeRangeUnit == 4) {
            mallocSprintf (comment, "%02d yr Prob of Hurricane Storm Surge > %g "
                           "m", lenTime, upperProb);
         } else {
            mallocSprintf (comment, "%02d hr Prob of Hurricane Storm Surge > %g "
                           "m", lenTime, upperProb);
         }
         *convert = UC_NONE;
         return;
      }
   }
   if (f_isNdfd) {
      /*
       * Deal with NDFD handling of Prob. Wind speeds.
       * There are different solutions for naming the Prob. Wind fields
       * Tim Boyer: TCWindSpdIncr34 TCWindSpdIncr50 TCWindSpdIncr64
       *            TCWindSpdCumu34 TCWindSpdCumu50 TCWindSpdCumu64
       * Dave Ruth: tcwspdabv34i tcwspdabv50i tcwspdabv64i
       *            tcwspdabv34c tcwspdabv50c tcwspdabv64c
       * AAT(Mine): ProbWindSpd34c ProbWindSpd50c ProbWindSpd64c
       *            ProbWindSpd34i ProbWindSpd50i ProbWindSpd64i
       */
      if ((prodType == 0) && (cat == 2) && (subcat == 1)) {
         myAssert (probType == 1);
         myAssert (lenTime > 0);
         if (timeIncrType == 2) {
            /* Incremental */
            mallocSprintf (name, "ProbWindSpd%02di",
                           (int) ((upperProb * 3600. / 1852.) + .5));
         } else {
            /* Cumulative */
            myAssert (timeIncrType == 192);
            mallocSprintf (name, "ProbWindSpd%02dc",
                           (int) ((upperProb * 3600. / 1852.) + .5));
         }
         if (timeRangeUnit == 3) {
            mallocSprintf (comment, "%02d mon Prob of Wind speed > %g m/s",
                           lenTime, upperProb);
         } else if (timeRangeUnit == 4) {
            mallocSprintf (comment, "%02d yr Prob of Wind speed > %g m/s",
                           lenTime, upperProb);
         } else {
            mallocSprintf (comment, "%02d hr Prob of Wind speed > %g m/s",
                           lenTime, upperProb);
         }
         *convert = UC_NONE;
         return;
      }
   }

   /* Only look at Generic tables if mstrVersion is not 255. */
   int gotRecordGeneric = -1;
   String pszShortName;
   String pszName;
   String pszUnit;
   if (mstrVersion != 255) {
       gotRecordGeneric = GetGrib2Table4_2_Record (prodType, cat, subcat,
                                            pszShortName, pszName, pszUnit,
                                            nullptr);
   }

   if (gotRecordGeneric && strcmp(pszName.c_str(), "Reserved for local use") == 0) {
       gotRecordGeneric = false;
   }

   if (gotRecordGeneric) {
         /* Check for NDFD over-rides. */
         /* The NDFD over-rides for probability templates have already been
          * handled. */
         if (lenTime > 0) {
            if (timeRangeUnit == 3) {
               mallocSprintf (name, "Prob%s%02dm", pszShortName.c_str(), lenTime);
               mallocSprintf (comment, "%02d mon Prob of %s ", lenTime,
                              pszName.c_str());
            } else if (timeRangeUnit == 4) {
               mallocSprintf (name, "Prob%s%02dy", pszShortName.c_str(), lenTime);
               mallocSprintf (comment, "%02d yr Prob of %s ", lenTime,
                              pszName.c_str());
            } else {
               mallocSprintf (name, "Prob%s%02d", pszShortName.c_str(), lenTime);
               mallocSprintf (comment, "%02d hr Prob of %s ", lenTime,
                              pszName.c_str());
            }
         } else {
            mallocSprintf (name, "Prob%s", pszShortName.c_str());
            mallocSprintf (comment, "Prob of %s ", pszName.c_str());
         }
         if (probType == 0) {
            if ((f_isNdfd || f_isMos) && (strcmp (pszShortName.c_str(), "TMP") == 0)) {
               reallocSprintf (comment, "below average");
               free (*name);
               if (lenTime > 0) {
                  if (timeRangeUnit == 3) {
                     mallocSprintf (name, "Prob%sBlw%02dm", pszShortName.c_str(), lenTime);
                  } else if (timeRangeUnit == 4) {
                     mallocSprintf (name, "Prob%sBlw%02dy", pszShortName.c_str(), lenTime);
                  } else {
                     mallocSprintf (name, "Prob%sBlw%02d", pszShortName.c_str(), lenTime);
                  }
               } else {
                  mallocSprintf (name, "Prob%sBlw", pszShortName.c_str());
               }
            } else {
               reallocSprintf (comment, "< %g %s", lowerProb, pszUnit.c_str());
            }
         } else if (probType == 1) {
            if ((f_isNdfd || f_isMos) && (strcmp (pszShortName.c_str(), "TMP") == 0)) {
               reallocSprintf (comment, "above average");
               free (*name);
               if (lenTime > 0) {
                  if (timeRangeUnit == 3) {
                     mallocSprintf (name, "Prob%sAbv%02dm", pszShortName.c_str(), lenTime);
                  } else if (timeRangeUnit == 4) {
                     mallocSprintf (name, "Prob%sAbv%02dy", pszShortName.c_str(), lenTime);
                  } else {
                     mallocSprintf (name, "Prob%sAbv%02d", pszShortName.c_str(), lenTime);
                  }
               } else {
                  mallocSprintf (name, "Prob%sAbv", pszShortName.c_str());
               }
            } else {
               reallocSprintf (comment, "> %g %s", upperProb, pszUnit.c_str());
            }
         } else if (probType == 2) {
            reallocSprintf (comment, ">= %g, < %g %s", lowerProb, upperProb,
                            pszUnit.c_str());
         } else if (probType == 3) {
            if ((f_isNdfd || f_isMos) && (strcmp (pszShortName.c_str(), "TMP") == 0)) {
               reallocSprintf (comment, "above average");
               free (*name);
               if (lenTime > 0) {
                  if (timeRangeUnit == 3) {
                     mallocSprintf (name, "Prob%sAbv%02dm", pszShortName.c_str(), lenTime);
                  } else if (timeRangeUnit == 4) {
                     mallocSprintf (name, "Prob%sAbv%02dy", pszShortName.c_str(), lenTime);
                  } else {
                     mallocSprintf (name, "Prob%sAbv%02d", pszShortName.c_str(), lenTime);
                  }
               } else {
                  mallocSprintf (name, "Prob%sAbv", pszShortName.c_str());
               }
            } else {
               reallocSprintf (comment, "> %g %s", lowerProb, pszUnit.c_str());
            }
         } else if (probType == 4) {
            if ((f_isNdfd || f_isMos) && (strcmp (pszShortName.c_str(), "TMP") == 0)) {
               reallocSprintf (comment, "below average");
               free (*name);
               if (lenTime > 0) {
                  if (timeRangeUnit == 3) {
                     mallocSprintf (name, "Prob%sBlw%02dm", pszShortName.c_str(), lenTime);
                  } else if (timeRangeUnit == 4) {
                     mallocSprintf (name, "Prob%sBlw%02dy", pszShortName.c_str(), lenTime);
                  } else {
                     mallocSprintf (name, "Prob%sBlw%02d", pszShortName.c_str(), lenTime);
                  }
               } else {
                  mallocSprintf (name, "Prob%sBlw", pszShortName.c_str());
               }
            } else {
               reallocSprintf (comment, "< %g %s", upperProb, pszUnit.c_str());
            }
         } else {
            reallocSprintf (comment, "%s", pszUnit.c_str());
         }
         *convert = UC_NONE;
         return;
   }

   /* Local use tables. */
   int gotRecordLocal = GetGrib2LocalTable4_2_Record (center, subcenter,
                                                 prodType, cat, subcat,
                                                 pszShortName, pszName, pszUnit,
                                                 nullptr);
   if (gotRecordLocal) {
            /* Ignore adding Prob prefix and "Probability of" to NDFD SPC prob
             * products. */
            if (lenTime > 0) {
               if (timeRangeUnit == 3) {
                  mallocSprintf (name, "Prob%s%02dm", pszShortName.c_str(), lenTime);
                  mallocSprintf (comment, "%02d mon Prob of %s ", lenTime,
                                 pszName.c_str());
               } else if (timeRangeUnit == 4) {
                  mallocSprintf (name, "Prob%s%02dy", pszShortName.c_str(), lenTime);
                  mallocSprintf (comment, "%02d yr Prob of %s ", lenTime,
                                 pszName.c_str());
               } else {
                  mallocSprintf (name, "Prob%s%02d", pszShortName.c_str(), lenTime);
                  mallocSprintf (comment, "%02d hr Prob of %s ", lenTime,
                                 pszName.c_str());
               }
            } else {
               mallocSprintf (name, "Prob%s", pszShortName.c_str());
               mallocSprintf (comment, "Prob of %s ", pszName.c_str());
            }
            if (probType == 0) {
               reallocSprintf (comment, "< %g %s", lowerProb,
                               pszUnit.c_str());
            } else if (probType == 1) {
               reallocSprintf (comment, "> %g %s", upperProb,
                               pszUnit.c_str());
            } else if (probType == 2) {
               reallocSprintf (comment, ">= %g, < %g %s", lowerProb,
                               upperProb, pszUnit.c_str());
            } else if (probType == 3) {
               reallocSprintf (comment, "> %g %s", lowerProb,
                               pszUnit.c_str());
            } else if (probType == 4) {
               reallocSprintf (comment, "< %g %s", upperProb,
                               pszUnit.c_str());
            } else {
               reallocSprintf (comment, "%s", pszUnit.c_str());
            }
            *convert = UC_NONE;
            return;
   }

   *name = (char *) malloc (strlen ("ProbUnknown") + 1);
   strcpy (*name, "ProbUnknown");
   mallocSprintf (comment, "Prob of (prodType %d, cat %d, subcat %d)",
                  prodType, cat, subcat);
   *convert = UC_NONE;
   return;
}

/* Deal with percentile templates 5/1/2006 */
static void ElemNamePerc (uChar mstrVersion, uShort2 center, uShort2 subcenter, int prodType,
                          int templat,
                          uChar cat, uChar subcat, sInt4 lenTime,
                          uChar timeRangeUnit,
                          sChar percentile, char **name, char **comment,
                          char **unit, int *convert)
{
   /* Only look at Generic tables if mstrVersion is not 255. */
   int gotRecordGeneric = -1;
   String pszShortName ;
   String pszName ;
   String pszUnit ;
   unit_convert unitConvert = UC_NONE;
   if (mstrVersion != 255) {
       gotRecordGeneric = GetGrib2Table4_2_Record (prodType, cat, subcat,
                                            pszShortName, pszName, pszUnit,
                                            &unitConvert);
   }

   if (gotRecordGeneric && strcmp(pszName.c_str(), "Reserved for local use") == 0) {
       gotRecordGeneric = false;
   }

   if (gotRecordGeneric) {
         /* Check for NDFD over-rides. */
         if (IsData_NDFD (center, subcenter) ||
             IsData_MOS (center, subcenter)) {
            for (size_t i = 0; i < (sizeof (NDFD_Override) /
                             sizeof (NDFD_AbrevOverrideTable)); i++) {
               if (strcmp (pszShortName.c_str(), "ASNOW") == 0) {
                 if (timeRangeUnit == 3) {
                    mallocSprintf (name, "%s%02dm%s%02dm", "Snow", lenTime, "e", percentile);
                    mallocSprintf (comment, "%02d mon %s Percentile(%d)", lenTime,
                                 pszName.c_str(), percentile);
                 } else if (timeRangeUnit == 4) {
                    mallocSprintf (name, "%s%02dy%s%02dy", "Snow", lenTime, "e", percentile);
                    mallocSprintf (comment, "%02d yr %s Percentile(%d)", lenTime,
                                   pszName.c_str(), percentile);
                 } else {
                    mallocSprintf (name, "%s%02d%s%02d", "Snow", lenTime, "e", percentile);
                    mallocSprintf (comment, "%02d hr %s Percentile(%d)", lenTime,
                                   pszName.c_str(), percentile);
                 }
                 mallocSprintf (unit, "[%s]", pszUnit.c_str());
                 *convert = unitConvert;
                 return;
               }
               if (strcmp (NDFD_Override[i].GRIB2name, pszShortName.c_str()) ==
                   0) {
                  mallocSprintf (name, "%s%02d", NDFD_Override[i].NDFDname,
                                 percentile);
                  if (lenTime > 0) {
                     if (timeRangeUnit == 3) {
                        mallocSprintf (comment, "%02d mon %s Percentile(%d)",
                                       lenTime, pszName.c_str(),
                                       percentile);
                     } else if (timeRangeUnit == 4) {
                        mallocSprintf (comment, "%02d yr %s Percentile(%d)",
                                       lenTime, pszName.c_str(),
                                       percentile);
                     } else {
                        mallocSprintf (comment, "%02d hr %s Percentile(%d)",
                                       lenTime, pszName.c_str(),
                                       percentile);
                     }
                  } else {
                     mallocSprintf (comment, "%s Percentile(%d)",
                                    pszName.c_str(), percentile);
                  }
                  mallocSprintf (unit, "[%s]", pszUnit.c_str());
                  *convert = unitConvert;
                  return;
               }
            }
         }
         mallocSprintf (name, "%s%02d", pszShortName.c_str(), percentile);
         if (lenTime > 0) {
            if (timeRangeUnit == 3) {
               mallocSprintf (comment, "%02d mon %s Percentile(%d)",
                              lenTime, pszName.c_str(), percentile);
            } else if (timeRangeUnit == 4) {
               mallocSprintf (comment, "%02d yr %s Percentile(%d)",
                              lenTime, pszName.c_str(), percentile);
            } else {
               mallocSprintf (comment, "%02d hr %s Percentile(%d)",
                              lenTime, pszName.c_str(), percentile);
            }
         } else {
            mallocSprintf (comment, "%s Percentile(%d)",
                           pszName.c_str(), percentile);
         }
         mallocSprintf (unit, "[%s]", pszUnit.c_str());
         *convert = unitConvert;
         return;
   }

   /* Local use tables. */
   int gotRecordLocal = GetGrib2LocalTable4_2_Record (center, subcenter,
                                             prodType, cat, subcat,
                                             pszShortName, pszName, pszUnit,
                                             &unitConvert);
   if (gotRecordLocal) {
/* If last two characters in name are numbers, then the name contains
 * the percentile (or exceedance value) so don't tack on percentile here.*/
            size_t len = strlen(pszShortName.c_str());
            if (len >= 2 /*&&
                isdigit(pszShortName[len -1]) &&
                isdigit(pszShortName[len -2])*/) {
               mallocSprintf (name, "%s", pszShortName.c_str());
            } else if ((strcmp (pszShortName.c_str(), "Surge") == 0) ||
                       (strcmp (pszShortName.c_str(), "SURGE") == 0)) {
/* Provide a special exception for storm surge exceedance.
 * Want exceedance value rather than percentile value.
 */
               mallocSprintf (name, "%s%02d", pszShortName.c_str(), 100 - percentile);
            } else {
               mallocSprintf (name, "%s%02d", pszShortName.c_str(), percentile);
            }

            if (lenTime > 0) {
               if (timeRangeUnit == 3) {
                  mallocSprintf (comment, "%02d mon %s Percentile(%d)",
                                 lenTime, pszName.c_str(), percentile);
               } else if (timeRangeUnit == 4) {
                  mallocSprintf (comment, "%02d yr %s Percentile(%d)",
                                 lenTime, pszName.c_str(), percentile);
               } else {
                  mallocSprintf (comment, "%02d hr %s Percentile(%d)",
                                 lenTime, pszName.c_str(), percentile);
               }
            } else {
               mallocSprintf (comment, "%s Percentile(%d)",
                              pszName.c_str(), percentile);
            }
            mallocSprintf (unit, "[%s]", pszUnit.c_str());
            *convert = unitConvert;
            return;
   }

   *name = (char *) malloc (strlen ("unknown") + 1);
   strcpy (*name, "unknown");
   mallocSprintf (comment, "(prodType %d, cat %d, subcat %d)", prodType,
                  cat, subcat);
   *unit = (char *) malloc (strlen ("[-]") + 1);
   strcpy (*unit, "[-]");
   *convert = UC_NONE;
   return;
}

///* Deal with non-prob templates 2/16/2006 */
static void ElemNameNorm (uChar mstrVersion, uShort2 center, uShort2 subcenter, int prodType,
                          int templat, uChar cat, uChar subcat, sInt4 lenTime,
                          uChar timeRangeUnit, uChar statProcessID,
                          uChar timeIncrType,
                          uChar genID,
                          uChar probType,
                          double lowerProb,
                          double upperProb,
                          char **name,
                          char **comment, char **unit, int *convert,
                          sChar f_fstValue, double fstSurfValue,
                          sChar f_sndValue, double sndSurfValue)
{
   sChar f_accum;
   /* float delt; */

   /* Check for over-ride case for ozone.  Originally just for NDFD, but I
    * think it is useful for ozone data that originated elsewhere. */
   if ((prodType == 0) && (templat == 8) && (cat == 14) && (subcat == 193)) {
      if (lenTime > 0) {
         if (timeRangeUnit == 3) {
            mallocSprintf (name, "Ozone%02dm", lenTime);
            mallocSprintf (comment, "%d mon Average Ozone Concentration", lenTime);
         } else if (timeRangeUnit == 4) {
            mallocSprintf (name, "Ozone%02dy", lenTime);
            mallocSprintf (comment, "%d yr Average Ozone Concentration", lenTime);
         } else {
            mallocSprintf (name, "Ozone%02d", lenTime);
            mallocSprintf (comment, "%d hr Average Ozone Concentration", lenTime);
         }
      } else {
         *name = (char *) malloc (strlen ("AVGOZCON") + 1);
         strcpy (*name, "AVGOZCON");
         *comment = (char *) malloc (strlen ("Average Ozone Concentration") +
                                     1);
         strcpy (*comment, "Average Ozone Concentration");
      }
      *unit = (char *) malloc (strlen ("[PPB]") + 1);
      strcpy (*unit, "[PPB]");
      *convert = UC_NONE;
      return;
   }
   /* Check for over-ride case for smokec / smokes. */
   if (center == 7) {
      if ((prodType == 0) && (cat == 13) && (subcat == 195)) {
         /* If NCEP/ARL (genID=6) then it is dust */
         if (genID == 6) {
            if (f_fstValue && f_sndValue) {
               const double delt = fstSurfValue - sndSurfValue;
               if ((delt <= 100) && (delt >= -100)) {
                  *name = (char *) malloc (strlen ("dusts") + 1);
                  strcpy (*name, "dusts");
                  *comment = (char *) malloc (strlen ("Surface level dust") + 1);
                  strcpy (*comment, "Surface level dust");
                  *unit = (char *) malloc (strlen ("[log10(10^-6g/m^3)]") + 1);
                  strcpy (*unit, "[log10(10^-6g/m^3)]");
                  *convert = UC_LOG10;
                  return;
               } else if ((delt <= 5000) && (delt >= -5000)) {
                  *name = (char *) malloc (strlen ("dustc") + 1);
                  strcpy (*name, "dustc");
                  *comment = (char *) malloc (strlen ("Average vertical column dust") + 1);
                  strcpy (*comment, "Average vertical column dust");
                  *unit = (char *) malloc (strlen ("[log10(10^-6g/m^3)]") + 1);
                  strcpy (*unit, "[log10(10^-6g/m^3)]");
                  *convert = UC_LOG10;
                  return;
               }
            }
         } else {
            if (f_fstValue && f_sndValue) {
               const double delt = fstSurfValue - sndSurfValue;
               if ((delt <= 100) && (delt >= -100)) {
                  *name = (char *) malloc (strlen ("smokes") + 1);
                  strcpy (*name, "smokes");
                  *comment = (char *) malloc (strlen ("Surface level smoke from fires") + 1);
                  strcpy (*comment, "Surface level smoke from fires");
                  *unit = (char *) malloc (strlen ("[log10(10^-6g/m^3)]") + 1);
                  strcpy (*unit, "[log10(10^-6g/m^3)]");
                  *convert = UC_LOG10;
                  return;
               } else if ((delt <= 5000) && (delt >= -5000)) {
                  *name = (char *) malloc (strlen ("smokec") + 1);
                  strcpy (*name, "smokec");
                  *comment = (char *) malloc (strlen ("Average vertical column smoke from fires") + 1);
                  strcpy (*comment, "Average vertical column smoke from fires");
                  *unit = (char *) malloc (strlen ("[log10(10^-6g/m^3)]") + 1);
                  strcpy (*unit, "[log10(10^-6g/m^3)]");
                  *convert = UC_LOG10;
                  return;
               }
            }
         }
      }
   }

   /* Only look at Generic tables if mstrVersion is not 255. */
   int gotRecordGeneric = -1;
   String pszShortName;
   String pszName;
   String pszUnit;
   unit_convert unitConvert = UC_NONE;
   if (mstrVersion != 255) {
       gotRecordGeneric = GetGrib2Table4_2_Record (prodType, cat, subcat,
                                            pszShortName, pszName, pszUnit,
                                            &unitConvert);
   }

   if (gotRecordGeneric && strcmp(pszName.c_str(), "Reserved for local use") == 0) {
       gotRecordGeneric = false;
   }

   if (gotRecordGeneric) {
         /* Check for NDFD over-rides. */
         if (IsData_MOS (center, subcenter)) {
            if (strcmp (pszShortName.c_str(), "APCP") == 0) {
               if (timeRangeUnit == 3) {
                  mallocSprintf (name, "%s%02dm", "QPF", lenTime);
                  mallocSprintf (comment, "%02d mon %s", lenTime,
                                 pszName.c_str());
               } else if (timeRangeUnit == 4) {
                  mallocSprintf (name, "%s%02dy", "QPF", lenTime);
                  mallocSprintf (comment, "%02d yr %s", lenTime,
                                 pszName.c_str());
               } else {
                  mallocSprintf (name, "%s%02d", "QPF", lenTime);
                  mallocSprintf (comment, "%02d hr %s", lenTime,
                                 pszName.c_str());
               }
               mallocSprintf (unit, "[%s]", pszUnit.c_str());
               *convert = unitConvert;
               return;
            }
            if (strcmp (pszShortName.c_str(), "ASNOW") == 0) {
               if (timeRangeUnit == 3) {
                  mallocSprintf (name, "%s%02dm", "SnowAmt", lenTime);
                  mallocSprintf (comment, "%02d mon %s", lenTime,
                                 pszName.c_str());
               } else if (timeRangeUnit == 4) {
                  mallocSprintf (name, "%s%02dy", "SnowAmt", lenTime);
                  mallocSprintf (comment, "%02d yr %s", lenTime,
                                 pszName.c_str());
               } else {
                  mallocSprintf (name, "%s%02d", "SnowAmt", lenTime);
                  mallocSprintf (comment, "%02d hr %s", lenTime,
                                 pszName.c_str());
               }
               mallocSprintf (unit, "[%s]", pszUnit.c_str());
               *convert = unitConvert;
               return;
            }
         }
         if (IsData_NDFD (center, subcenter) || IsData_MOS (center, subcenter)) {
            if (strcmp (pszShortName.c_str(), "EVP") == 0) {
               if (statProcessID == 10) {
                  mallocSprintf (name, "%s%02d", "EvpDep", lenTime);
                  mallocSprintf (comment, "%02d hr Evapo-Transpiration departure from normal",
                                 lenTime);
               } else {
                  mallocSprintf (name, "%s%02d", "Evp", lenTime);
                  mallocSprintf (comment, "%02d hr Evapo-Transpiration", lenTime);
               }
               mallocSprintf (unit, "[%s]", pszUnit.c_str());
               *convert = unitConvert;
               return;
            }
            for (size_t i = 0; i < (sizeof (NDFD_Override) /
                             sizeof (NDFD_AbrevOverrideTable)); i++) {
               if (strcmp (NDFD_Override[i].GRIB2name, pszShortName.c_str()) ==
                   0) {
                  *name = (char *) malloc (strlen (NDFD_Override[i].NDFDname) + 1);
                  strcpy (*name, NDFD_Override[i].NDFDname);
                  *comment = (char *) malloc (strlen (pszName.c_str()) + 1);
                  strcpy (*comment, pszName.c_str());
                  mallocSprintf (unit, "[%s]", pszUnit.c_str());
                  *convert = unitConvert;
                  return;
               }
            }
         }
         /* Allow hydrologic PoP, thunderstorm probability (TSTM), or APCP to
          * have lenTime labels. */
         //f_accum = (((prodType == 1) && (cat == 1) && (subcat == 2)) ||
         //           ((prodType == 0) && (cat == 19) && (subcat == 2)) ||
         //    ((prodType == 0) && (cat == 1) && (subcat == 8)) ||
         //    ((prodType == 0) && (cat == 2) && (subcat == 2)) ||
         //    ((prodType == 0) && (cat == 2) && (subcat == 3)) ||
         //    ((prodType == 0) && (cat == 19) && (subcat == 203)));
         //if (f_accum && (lenTime > 0)) {
         //   if (timeRangeUnit == 3) {
         //      mallocSprintf (name, "%s%02dm", pszShortName.c_str(), lenTime);
         //      mallocSprintf (comment, "%02d mon %s", lenTime,
         //                     pszName.c_str());
         //   } else if (timeRangeUnit == 4) {
         //      mallocSprintf (name, "%s%02dy", pszShortName.c_str(), lenTime);
         //      mallocSprintf (comment, "%02d yr %s", lenTime,
         //                     pszName.c_str());
         //   } else {
         //      mallocSprintf (name, "%s%02d", pszShortName.c_str(), lenTime);
         //      mallocSprintf (comment, "%02d hr %s", lenTime,
         //                     pszName.c_str());
         //   }
         //} else 
         {
            *name = (char *) malloc (strlen (pszShortName.c_str()) + 1);
            strcpy (*name, pszShortName.c_str());
            *comment = (char *) malloc (strlen (pszName.c_str()) + 1);
            strcpy (*comment, pszName.c_str());
         }
         mallocSprintf (unit, "[%s]", pszUnit.c_str());
         *convert = unitConvert;
         return;
   }

   /* Local use tables. */
   int gotRecordLocal = GetGrib2LocalTable4_2_Record (center, subcenter,
                                             prodType, cat, subcat,
                                             pszShortName, pszName, pszUnit,
                                             &unitConvert);
   if (gotRecordLocal) {
            /* Allow specific products with non-zero lenTime to reflect that.
             */
            {
               *name = (char *) malloc (strlen (pszShortName.c_str()) + 1);
               strcpy (*name, pszShortName.c_str());
               *comment = (char *) malloc (strlen (pszName.c_str()) + 1);
               strcpy (*comment, pszName.c_str());
            }
            mallocSprintf (unit, "[%s]", pszUnit.c_str());
            *convert = unitConvert;
            return;
   }

#if 1
   *name = (char*)malloc(strlen("VAR") + 1);
   strcpy(*name, "VAR");
   mallocSprintf(comment, "VAR%d-%d-%d_FROM_%d-%d", prodType,
       cat, subcat, center, subcenter);
#else
   *name = (char*)malloc(strlen("unknown") + 1);
   strcpy(*name, "unknown");
   mallocSprintf(comment, "(prodType %d, cat %d, subcat %d)", prodType,
       cat, subcat);
#endif
   *unit = (char *) malloc (strlen ("[-]") + 1);
   strcpy (*unit, "[-]");
   *convert = UC_NONE;
   return;
}

void ParseElemName (uChar mstrVersion, uShort2 center, uShort2 subcenter, int prodType,
                    int templat, int cat, int subcat, sInt4 lenTime,
                    uChar timeRangeUnit, uChar statProcessID,
                    uChar timeIncrType, uChar genID, uChar probType,
                    double lowerProb, double upperProb,
                    uChar derivedFcst,
                    char **name,
                    char **comment, char **unit, int *convert,
                    sChar percentile, uChar genProcess,
                    sChar f_fstValue, double fstSurfValue,
                    sChar f_sndValue, double sndSurfValue)
{
   char f_isNdfd = IsData_NDFD (center, subcenter);
   myAssert (*name == nullptr);
   myAssert (*comment == nullptr);
   myAssert (*unit == nullptr);

   /* Check if this is Probability data */
   if ((templat == GS4_PROBABIL_TIME) || (templat == GS4_PROBABIL_PNT)) {
      if (f_isNdfd && (prodType == 0) && (cat == 19)) {
         /* don't use ElemNameProb. */
         ElemNameNorm (mstrVersion, center, subcenter, prodType, templat, cat, subcat,
                       lenTime, timeRangeUnit, statProcessID, timeIncrType, genID, probType, lowerProb,
                       upperProb, name, comment, unit, convert, f_fstValue, fstSurfValue,
                       f_sndValue, sndSurfValue);

      } else {
         ElemNameProb (mstrVersion, center, subcenter, prodType, templat, cat, subcat,
                       lenTime, timeRangeUnit, timeIncrType, genID, probType, lowerProb,
                       upperProb, name, comment, unit, convert);
      }
   } else if ((templat == GS4_PERCENT_TIME) || (templat == GS4_PERCENT_PNT)) {
      ElemNamePerc (mstrVersion, center, subcenter, prodType, templat, cat, subcat,
                    lenTime, timeRangeUnit, percentile, name, comment, unit, convert);
   } else {
      ElemNameNorm (mstrVersion, center, subcenter, prodType, templat, cat, subcat,
                    lenTime, timeRangeUnit, statProcessID, timeIncrType, genID, probType, lowerProb,
                    upperProb, name, comment, unit, convert, f_fstValue, fstSurfValue,
                       f_sndValue, sndSurfValue);
   }

   // https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table4-7.shtml
   if( derivedFcst == 2 // Standard Deviation with respect to Cluster Mean
       || derivedFcst == 3 // Standard Deviation with respect to Cluster Mean, Normalized
       || derivedFcst == 4 // Spread of All Members
       || derivedFcst == 5 // Large Anomaly Index of All Members
       || derivedFcst == 7 // Interquartile Range (Range between the 25th and 75th quantile)
   )
   {
        const char* overrideUnit = nullptr;
        switch( derivedFcst )
        {
            case 2: overrideUnit = "[stddev]"; break;
            case 3: overrideUnit = "[stddev normalized]"; break;
            case 4: overrideUnit = "[spread]"; break;
            case 5: overrideUnit = "[large anomaly index]"; break;
            case 7: overrideUnit = "[interquantile range]"; break;
            default: break;
        }
        if( overrideUnit )
        {
            free(*unit);
            *unit = (char *) malloc (strlen (overrideUnit) + 1);
            strcpy (*unit, overrideUnit);
        }
        *convert = UC_NONE;
   }

   if ((genProcess == 6) || (genProcess == 7)) {
      *convert = UC_NONE;
      reallocSprintf (name, "ERR");
      reallocSprintf (comment, " error %s", *unit);
   } else {
      reallocSprintf (comment, " %s", *unit);
   }
}

/*****************************************************************************
 * ParseElemName2() -- Review 12/2002
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   Converts a prodType, template, category and subcategory quadruple to the
 * ASCII string abbreviation of that variable.
 *   For example: 0, 0, 0, 0, = "T" for temperature.
 *
 * ARGUMENTS
 * prodType = The GRIB2, section 0 product type. (Input)
 *  templat = The GRIB2 section 4 template number. (Input)
 *      cat = The GRIB2 section 4 "General category of Product." (Input)
 *   subcat = The GRIB2 section 4 "Specific subcategory of Product". (Input)
 *     name = Where to store the result (assumed already allocated to at
 *            least 15 bytes) (Output)
 *  comment = Extra info about variable (assumed already allocated to at
 *            least 100 bytes) (Output)
 *     unit = What unit this variable is in. (assumed already allocated to at
 *            least 20 bytes) (Output)
 *
 * FILES/DATABASES: None
 *
 * RETURNS: char *
 *   Same as 'strcpy', i.e. it returns name.
 *
 * HISTORY
 *   9/2002 Arthur Taylor (MDL/RSIS): Created.
 *  11/2002 AAT: Added MOIST_TOT_SNOW (and switched MOIST_SNOWAMT to
 *               SnowDepth)
 *  12/2002 (TK,AC,TB,&MS): Code Review.
 *   2/2003 AAT: moved from degrib.c to metaparse.c
 *              (Reason: primarily for Sect2 Parsing)
 *              (renamed from ElementName to ParseElemName)
 *   4/2003 AAT: Added the comment as a return element.(see GRIB2 discipline)
 *   6/2003 AAT: Added the unit as a return element.
 *   6/2003 AAT: Added Wave Height.
 *
 * NOTES
 *   Similar to GRIB1_Table2LookUp... May want to take this and the unit
 * stuff and combine them into a module.
 *****************************************************************************
 */
/*
static void ParseElemName2 (int prodType, int templat, int cat, int subcat,
                            char *name, char *comment, char *unit)
{
   if (prodType == 0) {
      if (cat == CAT_TEMP) { * 0 *
         switch (subcat) {
            case TEMP_TEMP: * 0 *
               strcpy (comment, "Temperature [K]");
               strcpy (name, "T");
               strcpy (unit, "[K]");
               return;
            case TEMP_MAXT: * 4 *
               strcpy (comment, "Maximum temperature [K]");
               strcpy (name, "MaxT");
               strcpy (unit, "[K]");
               return;
            case TEMP_MINT: * 5 *
               strcpy (comment, "Minimum temperature [K]");
               strcpy (name, "MinT");
               strcpy (unit, "[K]");
               return;
            case TEMP_DEW_TEMP: * 6 *
               strcpy (comment, "Dew point temperature [K]");
               strcpy (name, "Td");
               strcpy (unit, "[K]");
               return;
            case TEMP_WINDCHILL: * 13 *
               strcpy (comment, "Wind chill factor [K]");
               strcpy (name, "WCI");
               strcpy (unit, "[K]");
               return;
            case TEMP_HEAT: * 12 *
               strcpy (comment, "Heat index [K]");
               strcpy (name, "HeatIndex");
               strcpy (unit, "[K]");
               return;
         }
      } else if (cat == CAT_MOIST) { * 1 *
         switch (subcat) {
            case MOIST_REL_HUMID: * 1 *
               strcpy (comment, "Relative Humidity [%]");
               strcpy (name, "RH");
               strcpy (unit, "[%]");
               return;
            case MOIST_PRECIP_TOT: * 8 *
               if (templat == GS4_PROBABIL_TIME) { * template number 9 implies prob. *
                  strcpy (comment, "Prob of 0.01 In. of Precip [%]");
                  strcpy (name, "PoP12");
                  strcpy (unit, "[%]");
                  return;
               } else {
                  strcpy (comment, "Total precipitation [kg/(m^2)]");
                  strcpy (name, "QPF");
                  strcpy (unit, "[kg/(m^2)]");
                  return;
               }
            case MOIST_SNOWAMT: * 11 *
               strcpy (comment, "Snow Depth [m]");
               strcpy (name, "SnowDepth");
               strcpy (unit, "[m]");
               return;
            case MOIST_TOT_SNOW: * 29 *
               strcpy (comment, "Total snowfall [m]");
               strcpy (name, "SnowAmt");
               strcpy (unit, "[m]");
               return;
            case 192:  * local use moisture. *
               strcpy (comment, "Weather (local use moisture) [-]");
               strcpy (name, "Wx");
               strcpy (unit, "[-]");
               return;
         }
      } else if (cat == CAT_MOMENT) { * 2 *
         switch (subcat) {
            case MOMENT_WINDDIR: * 0 *
               strcpy (comment, "Wind direction (from which blowing) "
                       "[deg true]");
               strcpy (name, "WindDir");
               strcpy (unit, "[deg true]");
               return;
            case MOMENT_WINDSPD: * 1 *
               strcpy (comment, "Wind speed [m/s]");
               strcpy (name, "WindSpd");
               strcpy (unit, "[m/s]");
               return;
         }
      } else if (cat == CAT_CLOUD) { * 6 *
         switch (subcat) {
            case CLOUD_COVER: * 1 *
               strcpy (comment, "Total cloud cover [%]");
               strcpy (name, "Sky");
               strcpy (unit, "[%]");
               return;
         }
      } else if (cat == CAT_MOISTURE_PROB) { * 10 *
         if (subcat == 8) { * grandfather'ed in. *
            strcpy (comment, "Prob of 0.01 In. of Precip [%]");
            strcpy (name, "PoP12");
            strcpy (unit, "[%]");
            return;
         }
      }
   } else if (prodType == 10) {
      if (cat == OCEAN_CAT_WAVES) { * 0 *
         if (subcat == OCEAN_WAVE_SIG_HT_WV) { * 5 *
            strcpy (comment, "Significant height of wind waves [m]");
            strcpy (name, "WaveHeight");
            strcpy (unit, "[m]");
            return;
         }
      }
   }
   strcpy (name, "");
   strcpy (comment, "unknown");
   strcpy (unit, "[-]");
   return;
}
*/

/*****************************************************************************
 * ComputeUnit() --
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   Sets m, and b for equation y = mx + b, where x is in the unit
 * specified by GRIB2, and y is the one specified by f_unit.  The default
 * is m = 1, b = 0.
 *
 * Currently:
 *   For f_unit = 1 (English) we return Fahrenheit, knots, and inches for
 * temperature, wind speed, and amount of snow or rain.  The original units
 * are Kelvin, m/s, kg/m**2.
 *   For f_unit = 2 (metric) we return Celsius instead of Kelvin.
 *
 * ARGUMENTS
 *  convert = The enumerated type describing the type of conversion. (Input)
 * origName = Original unit name (needed for log10 option) (Input)
 *   f_unit = What type of unit to return (see above) (Input).
 *    unitM = M in equation y = m x + b (Output)
 *    unitB = B in equation y = m x + b (Output)
 *     name = Where to store the result (assumed already allocated to at
 *           least 15 bytes) (Output)
 *
 * FILES/DATABASES: None
 *
 * RETURNS: int
 *   0 if we set M and B, 1 if we used defaults.
 *
 * HISTORY
 *   1/2004 Arthur Taylor (MDL/RSIS): Re-Created.
 *
 * NOTES
 *****************************************************************************
 */
int ComputeUnit (int convert, char *origName, sChar f_unit, double *unitM,
                 double *unitB, char *name)
{
   switch (convert) {
      case UC_NONE:
         break;
      case UC_K2F:     /* Convert from Kelvin to F or C. */
         if (f_unit == 1) {
            strcpy (name, "[F]");
            *unitM = 9. / 5.;
            /* 32 - (9/5 * 273.15) = 32 - 491.67 = -459.67. */
            *unitB = -459.67;
            return 0;
         } else if (f_unit == 2) {
            strcpy (name, "[C]");
            *unitM = 1;
            *unitB = -273.15;
            return 0;
         }
         break;
      case UC_InchWater: /* Convert from kg/(m^2) to inches water. */
         if (f_unit == 1) {
            strcpy (name, "[inch]");
            /*
             * kg/m**2 / density of water (1000 kg/m**3)
             * 1/1000 m * 1/2.54 in/cm * 100 cm/m = 1/25.4 inches
             */
            *unitM = 1. / 25.4;
            *unitB = 0;
            return 0;
         }
         break;
      case UC_M2Feet:  /* Convert from meters to feet. */
         if (f_unit == 1) {
            /* 1 (m) * (100cm/m) * (inch/2.54cm) * (ft/12inch) = X (ft) */
            strcpy (name, "[feet]");
            *unitM = 100. / 30.48;
            *unitB = 0;
            return 0;
         }
         break;
      case UC_M2Inch:  /* Convert from meters to inches. */
         if (f_unit == 1) {
            strcpy (name, "[inch]");
            *unitM = 100. / 2.54; /* inch / m */
            *unitB = 0;
            return 0;
         }
         break;
      case UC_M2StatuteMile: /* Convert from meters to statute miles. */
         if (f_unit == 1) {
            strcpy (name, "[statute mile]");
            *unitM = 1. / 1609.344; /* mile / m */
            *unitB = 0;
            return 0;
         }
         break;
         /* NCEP goes with a convention of 1 nm = 1853.248 m.
          * http://www.sizes.com/units/mile_USnautical.htm Shows that on
          * 7/1/1954 US Department of Commerce switched to 1 nm = 1852 m
          * (International standard.) */
      case UC_MS2Knots: /* Convert from m/s to knots. */
         if (f_unit == 1) {
            strcpy (name, "[knots]");
            *unitM = 3600. / 1852.; /* knot / m s**-1 */
            *unitB = 0;
            return 0;
         }
         break;
      case UC_UVIndex: /* multiply by Watts/ m**2 by 40 for the UV index. */
         if (f_unit == 1) {
            strcpy (name, "[UVI]");
            *unitM = 40;
            *unitB = 0;
            return 0;
         }
         break;
      case UC_LOG10:   /* convert from log10 (x) to x */
         if ((f_unit == 1) || (f_unit == 2)) {
            origName[strlen (origName) - 2] = '\0';
            if (strlen (origName) > 21)
               origName[21] = '\0';
            snprintf (name, 15, "[%s]", origName + 7);
            *unitM = -10; /* M = -10 => take 10^(x) */
            *unitB = 0;
            return 0;
         }
         break;
   }
   /* Default case is for the unit in the GRIB2 document. */
   strcpy (name, "[GRIB2 unit]");
   *unitM = 1;
   *unitB = 0;
   return 1;
}

/*****************************************************************************
 * ComputeUnit2() --
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   Sets m, and b for equation y = mx + b, where x is in the unit
 * specified by GRIB2, and y is the one specified by f_unit.  The default
 * is m = 1, b = 0.
 *
 * Currently:
 *   For f_unit = 1 (English) we return Fahrenheit, knots, and inches for
 * temperature, wind speed, and amount of snow or rain.  The original units
 * are Kelvin, m/s, kg/m**2.
 *   For f_unit = 2 (metric) we return Celsius instead of Kelvin.
 *
 * ARGUMENTS
 * prodType = The GRIB2, section 0 product type. (Input)
 *  templat = The GRIB2 section 4 template number. (Input)
 *      cat = The GRIB2 section 4 "General category of Product." (Input)
 *   subcat = The GRIB2 section 4 "Specific subcategory of Product". (Input)
 *   f_unit = What type of unit to return (see above) (Input).
 *    unitM = M in equation y = m x + b (Output)
 *    unitB = B in equation y = m x + b (Output)
 *     name = Where to store the result (assumed already allocated to at
 *            least 15 bytes) (Output)
 *
 * FILES/DATABASES: None
 *
 * RETURNS: int
 *   0 if we set M and B, 1 if we used defaults.
 *
 * HISTORY
 *  11/2002 Arthur Taylor (MDL/RSIS): Created.
 *
 * NOTES
 *****************************************************************************
 */
/*
static int ComputeUnit2 (int prodType, int templat, int cat, int subcat,
                         sChar f_unit, double *unitM, double *unitB,
                         char *name)
{
   if (prodType == 0) {
      switch (cat) {
         case CAT_TEMP:
            * subcat 8 is K/m, 10, 11 is W/m**2 *
            if ((subcat < 16) && (subcat != 8) &&
                (subcat != 10) && (subcat != 11)) {
               if (f_unit == 1) {
                  strcpy (name, "[F]");
                  *unitM = 9. / 5.;
                  * 32 - (9/5 * 273.15) = 32 - 491.67 = -459.67. *
                  *unitB = -459.67;
                  return 0;
               } else if (f_unit == 2) {
                  strcpy (name, "[C]");
                  *unitM = 1;
                  *unitB = -273.15;
                  return 0;
               }
            }
            break;
         case CAT_MOIST:
            if (subcat == MOIST_PRECIP_TOT) {
               if (templat != 9) { * template number != 9 implies QPF. *
                  if (f_unit == 1) {
                     strcpy (name, "[inch]");
                     *
                      * kg/m**2 / density of water (1000 kg/m**3)
                      * 1/1000 m * 1/2.54 in/cm * 100 cm/m = 1/25.4 inches
                      *
                     *unitM = 1. / 25.4;
                     *unitB = 0;
                     return 0;
                  }
               }
            }
            if ((subcat == MOIST_SNOWAMT) || (subcat == MOIST_TOT_SNOW)) {
               if (f_unit == 1) {
                  strcpy (name, "[inch]");
                  *unitM = 100. / 2.54; * inch / m *
                  *unitB = 0;
                  return 0;
               }
            }
            break;
         case CAT_MOMENT:
            if (subcat == MOMENT_WINDSPD) {
               if (f_unit == 1) {
                  strcpy (name, "[knots]");
                  *unitM = 3600. / 1852.; * knot / m s**-1 *
                  *unitB = 0;
                  return 0;
               }
            }
            break;
      }
   } else if (prodType == 10) {
      if (cat == OCEAN_CAT_WAVES) { * 0 *
         if (subcat == OCEAN_WAVE_SIG_HT_WV) { * 5 *
            if (f_unit == 1) {
               * 1 (m) * (100cm/m) * (inch/2.54cm) * (ft/12inch) = X (ft) *
               strcpy (name, "[feet]");
               *unitM = 100. / 30.48;
               *unitB = 0;
               return 0;
            }
         }
      }
   }
   * Default case is for the unit in the GRIB2 document. *
   strcpy (name, "[GRIB2 unit]");
   *unitM = 1;
   *unitB = 0;
   return 1;
}
*/

/* GRIB2 Code Table 4.5 */
/* *INDENT-OFF* */


/*****************************************************************************
 * Table45Lookup() --
 *
 * Arthur Taylor / MDL
 *
 * PURPOSE
 *   To figure out the entry in the "Surface" table (used for Code Table 4.5)
 *
 * ARGUMENTS
 *       code = The original index to look up. (Input)
 *     center = Center code (Input)
 *  subcenter = Subcenter code (Input)
 * f_reserved = If the index is a "reserved" index (Output)
 *  shortName = Pointer to short name of the parameter, or nullptr(Output)
 *       name = Pointer to longer name of the parameter, or nullptr (Output)
 *       unit = Pointer to unit name, or nullptr (Output)
 * FILES/DATABASES: None
 *
 * RETURNS: TRUE in case of success

 * NOTES
 *****************************************************************************
 */
int  Table45Lookup (int code,
                    uShort2 center,
                    uShort2 /* subcenter */,
                    int *f_reserved,
                    String& shortName,
                    String& name,
                    String& unit
                    )
{
   *f_reserved = 1;
    shortName = "RESERVED";
    name = "Reserved";
    unit = "-";

   if ((code > 255) || (code < 0)) {
#ifdef DEBUG
      printf ("Surface index is out of 0..255 range?\n");
#endif
      return FALSE;
   }

   // Substantially changed by GDAL
   *f_reserved = 0;
   if( code > 191 && code < 255 && center != 7) {
       // Codes in range [192,254] are reserved for local use.
       // grib2_table_4_5.csv contains the codes valid for NCEP only
       // so for other centers, do not use the .csv file
        *f_reserved = 1;
        shortName = "RESERVED";
        name = "Reserved Local use";
        unit = "-";
        return TRUE;
   }

   const GRIB1SurfTable* table = &GRIB2Surface2[code];
   shortName = table->comment;
   name = table->name;
   unit = table->unit;
   return TRUE;
}

void ParseLevelName (unsigned short int center, unsigned short int subcenter,
                     uChar surfType, double value, sChar f_sndValue,
                     double sndValue, char **shortLevelName,
                     char **longLevelName)
{
   int f_reserved;
   char valBuff[512];
   char sndBuff[512];
   String surfshortname ;
   String surfname ;
   String surfunit ;
   Table45Lookup (surfType, center, subcenter,
                   &f_reserved, surfshortname, surfname, surfunit);

   /* Check if index is defined... 191 is undefined. */
   free (*shortLevelName);
   *shortLevelName = nullptr;
   free (*longLevelName);
   *longLevelName = nullptr;
   snprintf (valBuff, sizeof(valBuff), "%f", value);
   strTrimRight (valBuff, '0');
   if (valBuff[strlen (valBuff) - 1] == '.') {
      valBuff[strlen (valBuff) - 1] = '\0';
   }
   if (f_sndValue) {
      snprintf (sndBuff, sizeof(sndBuff), "%f", sndValue);
      strTrimRight (sndBuff, '0');
      if (sndBuff[strlen (sndBuff) - 1] == '.') {
         sndBuff[strlen (sndBuff) - 1] = '\0';
      }
      if (f_reserved) {
         reallocSprintf (shortLevelName, "%s-%s-%s(%d)", valBuff, sndBuff,
                         surfshortname.c_str(), surfType);
         reallocSprintf (longLevelName, "%s-%s[%s] %s(%d) (%s)", valBuff,
                         sndBuff, surfunit.c_str(), surfshortname.c_str(), surfType,
                         surfname.c_str());
      } else {
         reallocSprintf (shortLevelName, "%s-%s-%s", valBuff, sndBuff,
                         surfshortname.c_str());
         reallocSprintf (longLevelName, "%s-%s[%s] %s=\"%s\"", valBuff,
                         sndBuff, surfunit.c_str(), surfshortname.c_str(), surfname.c_str());
      }
   } else {
      if (f_reserved) {
         reallocSprintf (shortLevelName, "%s-%s(%d)", valBuff, surfshortname.c_str(),
                         surfType);
         reallocSprintf (longLevelName, "%s[%s] %s(%d) (%s)", valBuff,
                         surfunit.c_str(), surfshortname.c_str(), surfType, surfname.c_str());
      } else {
         reallocSprintf (shortLevelName, "%s-%s", valBuff, surfshortname.c_str());
         reallocSprintf (longLevelName, "%s[%s] %s=\"%s\"", valBuff,
                         surfunit.c_str(), surfshortname.c_str(), surfname.c_str());
      }
   }
}
